github.com/1aal/kubeblocks@v0.0.0-20231107070852-e1c03e598921/pkg/lorry/engines/postgres/manager_test.go (about) 1 /* 2 Copyright (C) 2022-2023 ApeCloud Co., Ltd 3 4 This file is part of KubeBlocks project 5 6 This program is free software: you can redistribute it and/or modify 7 it under the terms of the GNU Affero General Public License as published by 8 the Free Software Foundation, either version 3 of the License, or 9 (at your option) any later version. 10 11 This program is distributed in the hope that it will be useful 12 but WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 GNU Affero General Public License for more details. 15 16 You should have received a copy of the GNU Affero General Public License 17 along with this program. If not, see <http://www.gnu.org/licenses/>. 18 */ 19 20 package postgres 21 22 import ( 23 "context" 24 "fmt" 25 "testing" 26 27 "github.com/pashagolub/pgxmock/v2" 28 "github.com/shirou/gopsutil/v3/process" 29 "github.com/spf13/afero" 30 "github.com/stretchr/testify/assert" 31 32 "github.com/1aal/kubeblocks/pkg/constant" 33 "github.com/1aal/kubeblocks/pkg/lorry/dcs" 34 "github.com/1aal/kubeblocks/pkg/lorry/engines" 35 viper "github.com/1aal/kubeblocks/pkg/viperx" 36 ) 37 38 func MockDatabase(t *testing.T) (*Manager, pgxmock.PgxPoolIface, error) { 39 properties := map[string]string{ 40 ConnectionURLKey: "user=test password=test host=localhost port=5432 dbname=postgres", 41 } 42 testConfig, err := NewConfig(properties) 43 assert.NotNil(t, testConfig) 44 assert.Nil(t, err) 45 46 viper.Set(constant.KBEnvPodName, "test-pod-0") 47 viper.Set(constant.KBEnvClusterCompName, "test") 48 viper.Set(constant.KBEnvNamespace, "default") 49 viper.Set(PGDATA, "test") 50 mock, err := pgxmock.NewPool(pgxmock.MonitorPingsOption(true)) 51 if err != nil { 52 t.Fatal(err) 53 } 54 55 dbManager, err := NewManager(engines.Properties(properties)) 56 if err != nil { 57 t.Fatal(err) 58 } 59 60 manager := dbManager.(*Manager) 61 manager.Pool = mock 62 63 return manager, mock, err 64 } 65 66 func TestIsRunning(t *testing.T) { 67 manager, mock, _ := MockDatabase(t) 68 defer mock.Close() 69 70 t.Run("proc is nil, can't read file", func(t *testing.T) { 71 isRunning := manager.IsRunning() 72 assert.False(t, isRunning) 73 }) 74 75 t.Run("proc is not nil ,process is not exist", func(t *testing.T) { 76 manager.Proc = &process.Process{ 77 Pid: 100000, 78 } 79 80 isRunning := manager.IsRunning() 81 assert.False(t, isRunning) 82 }) 83 } 84 85 func TestNewProcessFromPidFile(t *testing.T) { 86 fs = afero.NewMemMapFs() 87 manager, mock, _ := MockDatabase(t) 88 defer mock.Close() 89 90 t.Run("file is not exist", func(t *testing.T) { 91 err := manager.newProcessFromPidFile() 92 assert.NotNil(t, err) 93 assert.ErrorContains(t, err, "file does not exist") 94 }) 95 96 t.Run("process is not exist", func(t *testing.T) { 97 data := "100000\n/postgresql/data\n1692770488\n5432\n/var/run/postgresql\n*\n 2388960 4\nready" 98 err := afero.WriteFile(fs, manager.DataDir+"/postmaster.pid", []byte(data), 0644) 99 if err != nil { 100 t.Fatal(err) 101 } 102 103 err = manager.newProcessFromPidFile() 104 assert.NotNil(t, err) 105 assert.ErrorContains(t, err, "process does not exist") 106 }) 107 } 108 109 func TestReadWrite(t *testing.T) { 110 ctx := context.TODO() 111 manager, mock, _ := MockDatabase(t) 112 defer mock.Close() 113 114 t.Run("write check success", func(t *testing.T) { 115 mock.ExpectExec(`create table if not exists`). 116 WillReturnResult(pgxmock.NewResult("CREATE TABLE", 0)) 117 118 ok := manager.WriteCheck(ctx, "") 119 assert.True(t, ok) 120 }) 121 122 t.Run("write check failed", func(t *testing.T) { 123 mock.ExpectExec(`create table if not exists`). 124 WillReturnError(fmt.Errorf("some error")) 125 126 ok := manager.WriteCheck(ctx, "") 127 assert.False(t, ok) 128 }) 129 130 t.Run("read check success", func(t *testing.T) { 131 mock.ExpectQuery("select"). 132 WillReturnRows(pgxmock.NewRows([]string{"check_ts"}).AddRow(1)) 133 134 ok := manager.ReadCheck(ctx, "") 135 assert.True(t, ok) 136 }) 137 138 t.Run("read check failed", func(t *testing.T) { 139 mock.ExpectQuery("select"). 140 WillReturnError(fmt.Errorf("some error")) 141 142 ok := manager.ReadCheck(ctx, "") 143 assert.False(t, ok) 144 }) 145 146 if err := mock.ExpectationsWereMet(); err != nil { 147 t.Errorf("there were unfulfilled expectations: %v", err) 148 } 149 } 150 151 func TestPgIsReady(t *testing.T) { 152 ctx := context.TODO() 153 manager, mock, _ := MockDatabase(t) 154 defer mock.Close() 155 156 t.Run("pg is ready", func(t *testing.T) { 157 mock.ExpectPing() 158 159 if isReady := manager.IsPgReady(ctx); !isReady { 160 t.Errorf("test pg is ready failed") 161 } 162 }) 163 164 t.Run("pg is not ready", func(t *testing.T) { 165 mock.ExpectPing().WillReturnError(fmt.Errorf("can't ping to db")) 166 if isReady := manager.IsPgReady(ctx); isReady { 167 t.Errorf("expect pg is not ready, but get ready") 168 } 169 }) 170 171 if err := mock.ExpectationsWereMet(); err != nil { 172 t.Errorf("there were unfulfilled expectations: %v", err) 173 } 174 } 175 176 func TestSetAndUnsetIsLeader(t *testing.T) { 177 manager, mock, _ := MockDatabase(t) 178 defer mock.Close() 179 180 t.Run("set is leader", func(t *testing.T) { 181 manager.SetIsLeader(true) 182 isSet, isLeader := manager.GetIsLeader() 183 assert.True(t, isSet) 184 assert.True(t, isLeader) 185 }) 186 187 t.Run("set is not leader", func(t *testing.T) { 188 manager.SetIsLeader(false) 189 isSet, isLeader := manager.GetIsLeader() 190 assert.True(t, isSet) 191 assert.False(t, isLeader) 192 }) 193 194 t.Run("unset is leader", func(t *testing.T) { 195 manager.UnsetIsLeader() 196 isSet, isLeader := manager.GetIsLeader() 197 assert.False(t, isSet) 198 assert.False(t, isLeader) 199 }) 200 } 201 202 func TestIsLeaderMember(t *testing.T) { 203 ctx := context.TODO() 204 manager, mock, _ := MockDatabase(t) 205 defer mock.Close() 206 cluster := &dcs.Cluster{} 207 currentMember := dcs.Member{ 208 Name: manager.CurrentMemberName, 209 } 210 211 t.Run("member is nil", func(t *testing.T) { 212 isLeaderMember, err := manager.IsLeaderMember(ctx, cluster, nil) 213 assert.False(t, isLeaderMember) 214 assert.NotNil(t, err) 215 }) 216 217 t.Run("leader member is nil", func(t *testing.T) { 218 isLeaderMember, err := manager.IsLeaderMember(ctx, cluster, ¤tMember) 219 assert.False(t, isLeaderMember) 220 assert.NotNil(t, err) 221 }) 222 223 cluster.Leader = &dcs.Leader{ 224 Name: manager.CurrentMemberName, 225 } 226 cluster.Members = append(cluster.Members, currentMember) 227 t.Run("is leader member", func(t *testing.T) { 228 isLeaderMember, err := manager.IsLeaderMember(ctx, cluster, ¤tMember) 229 assert.True(t, isLeaderMember) 230 assert.Nil(t, err) 231 }) 232 233 member := &dcs.Member{ 234 Name: "test", 235 } 236 t.Run("is not leader member", func(t *testing.T) { 237 isLeaderMember, err := manager.IsLeaderMember(ctx, cluster, member) 238 assert.False(t, isLeaderMember) 239 assert.Nil(t, err) 240 }) 241 } 242 243 func TestPgReload(t *testing.T) { 244 ctx := context.TODO() 245 manager, mock, _ := MockDatabase(t) 246 defer mock.Close() 247 248 t.Run("pg reload success", func(t *testing.T) { 249 mock.ExpectExec("select pg_reload_conf()"). 250 WillReturnResult(pgxmock.NewResult("select", 1)) 251 252 err := manager.PgReload(ctx) 253 assert.Nil(t, err) 254 }) 255 256 t.Run("pg reload failed", func(t *testing.T) { 257 mock.ExpectExec("select pg_reload_conf()"). 258 WillReturnError(fmt.Errorf("some error")) 259 260 err := manager.PgReload(ctx) 261 assert.NotNil(t, err) 262 }) 263 264 if err := mock.ExpectationsWereMet(); err != nil { 265 t.Errorf("there were unfulfilled expectations: %v", err) 266 } 267 } 268 269 func TestLock(t *testing.T) { 270 ctx := context.TODO() 271 manager, mock, _ := MockDatabase(t) 272 defer mock.Close() 273 274 t.Run("alter system failed", func(t *testing.T) { 275 mock.ExpectExec("alter system"). 276 WillReturnError(fmt.Errorf("alter system failed")) 277 278 err := manager.Lock(ctx, "test") 279 assert.NotNil(t, err) 280 assert.ErrorContains(t, err, "alter system failed") 281 }) 282 283 t.Run("pg reload failed", func(t *testing.T) { 284 mock.ExpectExec("alter system"). 285 WillReturnResult(pgxmock.NewResult("alter", 1)) 286 mock.ExpectExec("select pg_reload_conf()"). 287 WillReturnError(fmt.Errorf("pg reload failed")) 288 err := manager.Lock(ctx, "test") 289 assert.NotNil(t, err) 290 assert.ErrorContains(t, err, "pg reload failed") 291 }) 292 293 t.Run("lock success", func(t *testing.T) { 294 mock.ExpectExec("alter system"). 295 WillReturnResult(pgxmock.NewResult("alter", 1)) 296 mock.ExpectExec("select pg_reload_conf()"). 297 WillReturnResult(pgxmock.NewResult("select", 1)) 298 err := manager.Lock(ctx, "test") 299 assert.Nil(t, err) 300 }) 301 302 if err := mock.ExpectationsWereMet(); err != nil { 303 t.Errorf("there were unfulfilled expectations: %v", err) 304 } 305 } 306 307 func TestUnlock(t *testing.T) { 308 ctx := context.TODO() 309 manager, mock, _ := MockDatabase(t) 310 defer mock.Close() 311 312 t.Run("alter system failed", func(t *testing.T) { 313 mock.ExpectExec("alter system"). 314 WillReturnError(fmt.Errorf("alter system failed")) 315 316 err := manager.Unlock(ctx) 317 assert.NotNil(t, err) 318 assert.ErrorContains(t, err, "alter system failed") 319 }) 320 321 t.Run("pg reload failed", func(t *testing.T) { 322 mock.ExpectExec("alter system"). 323 WillReturnResult(pgxmock.NewResult("alter", 1)) 324 mock.ExpectExec("select pg_reload_conf()"). 325 WillReturnError(fmt.Errorf("pg reload failed")) 326 err := manager.Unlock(ctx) 327 assert.NotNil(t, err) 328 assert.ErrorContains(t, err, "pg reload failed") 329 }) 330 331 t.Run("unlock success", func(t *testing.T) { 332 mock.ExpectExec("alter system"). 333 WillReturnResult(pgxmock.NewResult("alter", 1)) 334 mock.ExpectExec("select pg_reload_conf()"). 335 WillReturnResult(pgxmock.NewResult("select", 1)) 336 err := manager.Unlock(ctx) 337 assert.Nil(t, err) 338 }) 339 340 if err := mock.ExpectationsWereMet(); err != nil { 341 t.Errorf("there were unfulfilled expectations: %v", err) 342 } 343 }