decred.org/dcrdex@v1.0.5/server/db/driver/pg/system_online_test.go (about) 1 //go:build pgonline 2 3 package pg 4 5 import ( 6 "context" 7 "database/sql" 8 "fmt" 9 "os" 10 "testing" 11 12 "decred.org/dcrdex/dex" 13 ) 14 15 const ( 16 PGTestsHost = "localhost" // "/run/postgresql" for UNIX socket 17 PGTestsPort = "5432" // "" for UNIX socket 18 PGTestsUser = "dcrdex" // "dcrdex" for full database rather than test data repo 19 PGTestsPass = "" 20 PGTestsDBName = "dcrdex_mainnet_test" 21 ) 22 23 var ( 24 archie *Archiver 25 mktInfo, mktInfo2 *dex.MarketInfo 26 numMarkets int 27 ) 28 29 func TestMain(m *testing.M) { 30 startLogger() 31 32 // Wrap openDB so that the cleanUp function may be deferred. 33 doIt := func() int { 34 // Not counted as coverage, must test Archiver constructor explicitly. 35 cleanUp, err := openDB() 36 defer cleanUp() 37 if err != nil { 38 panic(fmt.Sprintln("no db for testing:", err)) 39 } 40 41 return m.Run() 42 } 43 44 os.Exit(doIt()) 45 } 46 47 func openDB() (func() error, error) { 48 var err error 49 mktInfo, err = dex.NewMarketInfoFromSymbols("dcr", "btc", LotSize, RateStep, EpochDuration, 0, MarketBuyBuffer) 50 if err != nil { 51 return func() error { return nil }, fmt.Errorf("invalid market: %v", err) 52 } 53 54 mktInfo2, err = dex.NewMarketInfoFromSymbols("btc", "ltc", LotSize, RateStep, EpochDuration, 0, MarketBuyBuffer) 55 if err != nil { 56 return func() error { return nil }, fmt.Errorf("invalid market: %v", err) 57 } 58 59 AssetDCR = mktInfo.Base 60 AssetBTC = mktInfo.Quote 61 AssetLTC = mktInfo2.Quote 62 63 dbi := Config{ 64 Host: PGTestsHost, 65 Port: PGTestsPort, 66 User: PGTestsUser, 67 Pass: PGTestsPass, 68 DBName: PGTestsDBName, 69 ShowPGConfig: false, 70 QueryTimeout: 0, // zero to use the default 71 MarketCfg: []*dex.MarketInfo{mktInfo, mktInfo2}, 72 } 73 74 numMarkets = len(dbi.MarketCfg) 75 76 closeFn := func() error { return nil } 77 78 // Low-level db connection to kill any leftover tables. 79 db, err := connect(dbi.Host, dbi.Port, dbi.User, dbi.Pass, dbi.DBName) 80 if err != nil { 81 return closeFn, err 82 } 83 if err := nukeAll(db); err != nil { 84 return closeFn, fmt.Errorf("nukeAll: %v", err) 85 } 86 if err = db.Close(); err != nil { 87 return closeFn, fmt.Errorf("failed to close DB: %v", err) 88 } 89 90 ctx := context.Background() 91 archie, err = NewArchiver(ctx, &dbi) 92 if archie == nil { 93 return closeFn, err 94 } 95 96 closeFn = func() error { 97 if err := nukeAll(archie.db); err != nil { 98 log.Errorf("nukeAll: %v", err) 99 } 100 return archie.Close() 101 } 102 103 return closeFn, err 104 } 105 106 func detectMarkets(db *sql.DB) ([]string, error) { 107 // Identify all markets by matching schemas like dcr_btc with '___\____'. 108 rows, err := db.Query(`select nspname from pg_catalog.pg_namespace where nspname like '___\____';`) 109 if err != nil { 110 return nil, err 111 } 112 defer rows.Close() 113 114 var markets []string 115 for rows.Next() { 116 var market string 117 if err = rows.Scan(&market); err != nil { 118 rows.Close() 119 return nil, err 120 } 121 markets = append(markets, market) 122 } 123 124 if err = rows.Err(); err != nil { 125 return nil, err 126 } 127 128 return markets, nil 129 } 130 131 // nukeAll removes all of the market schemas and the tables within them, as well 132 // as all of the DEX tables in the public schema. 133 // TODO: find a long term home for this once it is clear if and how it will be 134 // used outside of tests. 135 func nukeAll(db *sql.DB) error { 136 markets, err := detectMarkets(db) 137 if err != nil { 138 return fmt.Errorf("failed to detect markets: %v", err) 139 } 140 141 // Drop market schemas. 142 for i := range markets { 143 log.Tracef(`Dropping market %s schema...`, markets[i]) 144 _, err = db.Exec(fmt.Sprintf("DROP SCHEMA %s CASCADE;", markets[i])) 145 if err != nil { 146 return err 147 } 148 } 149 150 // Drop tables in public schema. 151 dropPublic := func(stmts []tableStmt) error { 152 for i := range stmts { 153 tableName := "public." + stmts[i].name 154 log.Tracef(`Dropping DEX table %s...`, tableName) 155 if err = dropTable(db, tableName); err != nil { 156 return err 157 } 158 } 159 return nil 160 } 161 162 err = dropPublic(createDEXTableStatements) 163 if err != nil { 164 return err 165 } 166 167 return dropPublic(createAccountTableStatements) 168 } 169 170 func cleanTables(db *sql.DB) error { 171 err := nukeAll(db) 172 if err != nil { 173 return err 174 } 175 _, err = prepareTables(context.Background(), db, mktConfig()) 176 return err 177 } 178 179 func Test_sqlExec(t *testing.T) { 180 // Expect to update 0 rows. 181 stmt := fmt.Sprintf(`UPDATE %s SET lot_size=1234 WHERE name='definitely not a market';`, marketsTableName) 182 N, err := sqlExec(archie.db, stmt) 183 if err != nil { 184 t.Fatal("sqlExec:", err) 185 } 186 if N != 0 { 187 t.Errorf("Should have updated 0 rows without error, got %d", N) 188 } 189 190 // Expect to update 1 rows. 191 stmt = fmt.Sprintf(`UPDATE %s SET lot_size=lot_size WHERE name=$1;`, 192 marketsTableName) 193 N, err = sqlExec(archie.db, stmt, mktInfo.Name) 194 if err != nil { 195 t.Fatal("sqlExec:", err) 196 } 197 if N != 1 { 198 t.Errorf("Should have updated 1 rows without error, got %d", N) 199 } 200 201 // Expect to update N=numMarkets rows. 202 stmt = fmt.Sprintf(`UPDATE %s SET lot_size=lot_size;`, 203 marketsTableName) 204 N, err = sqlExec(archie.db, stmt) 205 if err != nil { 206 t.Fatal("sqlExec:", err) 207 } 208 if N != int64(numMarkets) { 209 t.Errorf("Should have updated %d rows without error, got %d", numMarkets, N) 210 } 211 } 212 213 func Test_checkCurrentTimeZone(t *testing.T) { 214 currentTZ, err := checkCurrentTimeZone(archie.db) 215 if err != nil { 216 t.Fatal(err) 217 } 218 t.Logf("Set time zone: %v", currentTZ) 219 } 220 221 func Test_retrieveSysSettingsConfFile(t *testing.T) { 222 ss, err := retrieveSysSettingsConfFile(archie.db) 223 if err != nil && err != sql.ErrNoRows { 224 t.Errorf("Failed to retrieve system settings: %v", err) 225 } 226 t.Logf("\n%v", ss) 227 } 228 229 func Test_retrieveSysSettingsPerformance(t *testing.T) { 230 ss, err := retrieveSysSettingsPerformance(archie.db) 231 if err != nil { 232 t.Errorf("Failed to retrieve system settings: %v", err) 233 } 234 t.Logf("\n%v", ss) 235 } 236 237 func Test_retrieveSysSettingsServer(t *testing.T) { 238 ss, err := retrieveSysSettingsServer(archie.db) 239 if err != nil { 240 t.Errorf("Failed to retrieve system server: %v", err) 241 } 242 t.Logf("\n%v", ss) 243 } 244 245 func Test_retrievePGVersion(t *testing.T) { 246 ver, err := retrievePGVersion(archie.db) 247 if err != nil { 248 t.Errorf("Failed to retrieve postgres version: %v", err) 249 } 250 t.Logf("\n%s", ver) 251 }