github.com/square/finch@v0.0.0-20240412205204-6530c03e2b96/boot/scope_test.go (about) 1 package boot_test 2 3 import ( 4 "context" 5 "database/sql" 6 "fmt" 7 "os" 8 "testing" 9 10 "github.com/go-test/deep" 11 12 "github.com/square/finch/boot" 13 "github.com/square/finch/test" 14 ) 15 16 var ( 17 dsn string 18 db *sql.DB 19 ) 20 21 func setup(t *testing.T) { 22 var err error 23 var queries []string 24 if dsn == "" || db == nil { 25 dsn, db, err = test.Connection() 26 if err != nil { 27 t.Fatal(err) 28 } 29 queries = []string{ 30 "CREATE DATABASE IF NOT EXISTS finch", 31 "USE finch", 32 "DROP TABLE IF EXISTS scopetest", 33 "CREATE TABLE scopetest (id int auto_increment primary key not null, eg int, cg int, c int, iter int, trx int, s int, a int, r int)", 34 } 35 } else { 36 queries = []string{ 37 "USE finch", 38 "TRUNCATE TABLE scopetest", 39 } 40 } 41 if err := test.Exec(db, queries); err != nil { 42 t.Fatal(err) 43 } 44 } 45 46 func results() ([][]int, error) { 47 rows, err := db.QueryContext(context.Background(), "select eg, cg, c, iter, trx, s, a, r from finch.scopetest order by eg, cg, c, iter, trx, s") 48 if err != nil { 49 return nil, err 50 } 51 defer rows.Close() 52 res := [][]int{} 53 for rows.Next() { 54 cols := make([]int, 8) 55 ptr := make([]interface{}, len(cols)) 56 for i := range ptr { 57 ptr[i] = &cols[i] 58 } 59 if err = rows.Scan(ptr...); err != nil { 60 return nil, err 61 } 62 res = append(res, cols) 63 } 64 return res, nil 65 } 66 67 const ( 68 EG int = iota 69 CG 70 C 71 ITER 72 TRX 73 S 74 A 75 R 76 ) 77 78 func colVals(col int, rows [][]int) []int { 79 vals := make([]int, len(rows)) 80 for i := range rows { 81 vals[i] = rows[i][col] 82 } 83 return vals 84 } 85 86 func hasPattern(p string, vals []int) (bool, string) { 87 az := 96 // 97=a 88 seen := map[int]bool{} 89 q := "" 90 for _, v := range vals { 91 if !seen[v] { 92 az += 1 // a, c, ... 93 seen[v] = true 94 } 95 q += fmt.Sprintf("%c", az) 96 } 97 return p == q, q 98 } 99 100 func run(t *testing.T, file string) ([][]int, error) { 101 setup(t) 102 defer os.Chdir(cwd) // Finch will cd to stage file dir 103 env := boot.Env{ 104 Args: []string{ 105 "./finch", // fake like it was run from cmd line (required) 106 "-D", "finch", 107 "--dsn", dsn, 108 "../test/run/scope/" + file, 109 }, 110 } 111 err := boot.Up(env) 112 if err != nil { 113 return nil, err 114 } 115 rows, err := results() 116 if err != nil { 117 return nil, err 118 } 119 if len(rows) != 12 { 120 return nil, fmt.Errorf("got %d rows, expected 12", len(rows)) 121 } 122 return rows, nil 123 } 124 125 // -------------------------------------------------------------------------- 126 127 func TestScope_Statement(t *testing.T) { 128 if test.Build { 129 t.Skip("GitHub Actions build") 130 } 131 rows, err := run(t, "statement.yaml") 132 if err != nil { 133 t.Fatal(err) 134 } 135 136 /* 137 +------+------+------+------+------+------+------+--------+ 138 | eg | cg | c | iter | trx | s | a | r | 139 +------+------+------+------+------+------+------+--------+ 140 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 550747 | 141 | 1 | 1 | 1 | 1 | 1 | 2 | 1 | 736643 | 142 | 1 | 1 | 1 | 1 | 2 | 3 | 1 | 421079 | 143 | 1 | 1 | 1 | 2 | 3 | 4 | 2 | 662756 | 144 | 1 | 1 | 1 | 2 | 3 | 5 | 2 | 135600 | 145 | 1 | 1 | 1 | 2 | 4 | 6 | 2 | 331290 | 146 | 1 | 2 | 1 | 1 | 1 | 1 | 1 | 952510 | 147 | 1 | 2 | 1 | 1 | 1 | 2 | 1 | 163171 | 148 | 1 | 2 | 1 | 1 | 2 | 3 | 1 | 979482 | 149 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 351387 | 150 | 2 | 1 | 1 | 1 | 1 | 2 | 1 | 702906 | 151 | 2 | 1 | 1 | 1 | 2 | 3 | 1 | 198349 | 152 +------+------+------+------+------+------+------+--------+ 153 */ 154 155 // A (auto-inc) values equal the above ^ example 156 got := colVals(A, rows) 157 expect := []int{1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1} 158 if diff := deep.Equal(got, expect); diff != nil { 159 t.Errorf("wrong auto-inc values: %v", diff) 160 } 161 162 got = colVals(R, rows) 163 seen := map[int]bool{} 164 for _, i := range got { 165 if seen[i] { 166 t.Errorf("same random value with statement scope, expected all random values (or 1 in a 1,000,000 chance @r generated same random value): %d", i) 167 } 168 } 169 } 170 171 func TestScope_Trx(t *testing.T) { 172 if test.Build { 173 t.Skip("GitHub Actions build") 174 } 175 176 rows, err := run(t, "trx.yaml") 177 if err != nil { 178 t.Fatal(err) 179 } 180 181 /* 182 +------+------+------+------+------+------+------+--------+ 183 | eg | cg | c | iter | trx | s | a | r | 184 +------+------+------+------+------+------+------+--------+ 185 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 566273 | a 186 | 1 | 1 | 1 | 1 | 1 | 2 | 1 | 566273 | a 187 | 1 | 1 | 1 | 1 | 2 | 3 | 1 | 995357 | b 188 | 1 | 1 | 1 | 2 | 3 | 4 | 2 | 919473 | c 189 | 1 | 1 | 1 | 2 | 3 | 5 | 2 | 919473 | c 190 | 1 | 1 | 1 | 2 | 4 | 6 | 2 | 509510 | d 191 | 1 | 2 | 1 | 1 | 1 | 1 | 1 | 151654 | e 192 | 1 | 2 | 1 | 1 | 1 | 2 | 1 | 151654 | e 193 | 1 | 2 | 1 | 1 | 2 | 3 | 1 | 418694 | f 194 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 495910 | g 195 | 2 | 1 | 1 | 1 | 1 | 2 | 1 | 495910 | g 196 | 2 | 1 | 1 | 1 | 2 | 3 | 1 | 841785 | h 197 +------+------+------+------+------+------+------+--------+ 198 */ 199 200 // A (auto-inc) values equal the above ^ example, which is same as statement 201 // scope, so looking at r for trx scope is better (below) 202 got := colVals(A, rows) 203 expect := []int{1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1} 204 if diff := deep.Equal(got, expect); diff != nil { 205 t.Errorf("wrong auto-inc values: %v", diff) 206 } 207 208 // Check that random numbers repeat as expected by reducing each unique 209 // value to a, b, c, etc. then comparing the patterns 210 rVals := colVals(R, rows) 211 p := "aabccdeefggh" 212 if ok, q := hasPattern(p, rVals); !ok { 213 t.Errorf("random vals %v have pattern %s, expected %s ", rVals, q, p) 214 } 215 } 216 217 func TestScope_Iter(t *testing.T) { 218 if test.Build { 219 t.Skip("GitHub Actions build") 220 } 221 222 rows, err := run(t, "iter.yaml") 223 if err != nil { 224 t.Fatal(err) 225 } 226 227 /* 228 +------+------+------+------+------+------+------+--------+ 229 | eg | cg | c | iter | trx | s | a | r | 230 +------+------+------+------+------+------+------+--------+ 231 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 304611 | a 232 | 1 | 1 | 1 | 1 | 1 | 2 | 1 | 304611 | a 233 | 1 | 1 | 1 | 1 | 2 | 3 | 1 | 304611 | a 234 | 1 | 1 | 1 | 2 | 3 | 4 | 2 | 945546 | b 235 | 1 | 1 | 1 | 2 | 3 | 5 | 2 | 945546 | b 236 | 1 | 1 | 1 | 2 | 4 | 6 | 2 | 945546 | b 237 | 1 | 2 | 1 | 1 | 1 | 1 | 1 | 777638 | c 238 | 1 | 2 | 1 | 1 | 1 | 2 | 1 | 777638 | c 239 | 1 | 2 | 1 | 1 | 2 | 3 | 1 | 777638 | c 240 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 553149 | d 241 | 2 | 1 | 1 | 1 | 1 | 2 | 1 | 553149 | d 242 | 2 | 1 | 1 | 1 | 2 | 3 | 1 | 553149 | d 243 +------+------+------+------+------+------+------+--------+ 244 */ 245 246 // A (auto-inc) values equal the above ^ example, which is same as statement 247 // scope, so looking at r for trx scope is better (below) 248 got := colVals(A, rows) 249 expect := []int{1, 1, 1, 2, 2, 2, 1, 1, 1, 1, 1, 1} 250 if diff := deep.Equal(got, expect); diff != nil { 251 t.Errorf("wrong auto-inc values: %v", diff) 252 } 253 254 // See previous test 255 rVals := colVals(R, rows) 256 p := "aaabbbcccddd" 257 if ok, q := hasPattern(p, rVals); !ok { 258 t.Errorf("random vals %v have pattern %s, expected %s ", rVals, q, p) 259 } 260 } 261 262 func TestScope_Client(t *testing.T) { 263 if test.Build { 264 t.Skip("GitHub Actions build") 265 } 266 267 rows, err := run(t, "client.yaml") 268 if err != nil { 269 t.Fatal(err) 270 } 271 272 /* 273 +------+------+------+------+------+------+------+--------+ 274 | eg | cg | c | iter | trx | s | a | r | 275 +------+------+------+------+------+------+------+--------+ 276 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 782998 | a 277 | 1 | 1 | 1 | 1 | 1 | 2 | 1 | 782998 | a 278 | 1 | 1 | 1 | 1 | 2 | 3 | 1 | 782998 | a 279 | 1 | 1 | 1 | 2 | 3 | 4 | 1 | 782998 | a 280 | 1 | 1 | 1 | 2 | 3 | 5 | 1 | 782998 | a 281 | 1 | 1 | 1 | 2 | 4 | 6 | 1 | 782998 | a 282 | 1 | 2 | 1 | 1 | 1 | 1 | 1 | 88789 | b 283 | 1 | 2 | 1 | 1 | 1 | 2 | 1 | 88789 | b 284 | 1 | 2 | 1 | 1 | 2 | 3 | 1 | 88789 | b 285 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 93318 | c 286 | 2 | 1 | 1 | 1 | 1 | 2 | 1 | 93318 | c 287 | 2 | 1 | 1 | 1 | 2 | 3 | 1 | 93318 | c 288 +------+------+------+------+------+------+------+--------+ 289 */ 290 291 got := colVals(A, rows) 292 expect := []int{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1} 293 if diff := deep.Equal(got, expect); diff != nil { 294 t.Errorf("wrong auto-inc values: %v", diff) 295 } 296 297 // See previous test 298 rVals := colVals(R, rows) 299 p := "aaaaaabbbccc" 300 if ok, q := hasPattern(p, rVals); !ok { 301 t.Errorf("random vals %v have pattern %s, expected %s ", rVals, q, p) 302 } 303 }