github.com/jgbaldwinbrown/perf@v0.1.1/storage/db/db_test.go (about) 1 // Copyright 2017 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build cgo 6 // +build cgo 7 8 package db_test 9 10 import ( 11 "bytes" 12 "fmt" 13 "reflect" 14 "sort" 15 "strconv" 16 "strings" 17 "testing" 18 "time" 19 20 "golang.org/x/net/context" 21 "golang.org/x/perf/internal/diff" 22 "golang.org/x/perf/storage/benchfmt" 23 . "golang.org/x/perf/storage/db" 24 "golang.org/x/perf/storage/db/dbtest" 25 ) 26 27 // Most of the db package is tested via the end-to-end-tests in perf/storage/app. 28 29 // TestUploadIDs verifies that NewUpload generates the correct sequence of upload IDs. 30 func TestUploadIDs(t *testing.T) { 31 ctx := context.Background() 32 33 db, cleanup := dbtest.NewDB(t) 34 defer cleanup() 35 36 defer SetNow(time.Time{}) 37 38 tests := []struct { 39 sec int64 40 id string 41 }{ 42 {0, "19700101.1"}, 43 {0, "19700101.2"}, 44 {86400, "19700102.1"}, 45 {86400, "19700102.2"}, 46 {86400, "19700102.3"}, 47 {86400, "19700102.4"}, 48 {86400, "19700102.5"}, 49 {86400, "19700102.6"}, 50 {86400, "19700102.7"}, 51 {86400, "19700102.8"}, 52 {86400, "19700102.9"}, 53 {86400, "19700102.10"}, 54 {86400, "19700102.11"}, 55 } 56 for _, test := range tests { 57 SetNow(time.Unix(test.sec, 0)) 58 u, err := db.NewUpload(ctx) 59 if err != nil { 60 t.Fatalf("NewUpload: %v", err) 61 } 62 if err := u.Commit(); err != nil { 63 t.Fatalf("Commit: %v", err) 64 } 65 if u.ID != test.id { 66 t.Fatalf("u.ID = %q, want %q", u.ID, test.id) 67 } 68 } 69 } 70 71 // checkQueryResults performs a query on db and verifies that the 72 // results as printed by BenchmarkPrinter are equal to results. 73 func checkQueryResults(t *testing.T, db *DB, query, results string) { 74 q := db.Query(query) 75 defer q.Close() 76 77 var buf bytes.Buffer 78 bp := benchfmt.NewPrinter(&buf) 79 80 for q.Next() { 81 if err := bp.Print(q.Result()); err != nil { 82 t.Fatalf("Print: %v", err) 83 } 84 } 85 if err := q.Err(); err != nil { 86 t.Fatalf("Err: %v", err) 87 } 88 if diff := diff.Diff(buf.String(), results); diff != "" { 89 t.Errorf("wrong results: (- have/+ want)\n%s", diff) 90 } 91 } 92 93 // TestReplaceUpload verifies that the expected number of rows exist after replacing an upload. 94 func TestReplaceUpload(t *testing.T) { 95 SetNow(time.Unix(0, 0)) 96 defer SetNow(time.Time{}) 97 db, cleanup := dbtest.NewDB(t) 98 defer cleanup() 99 100 ctx := context.Background() 101 102 labels := benchfmt.Labels{"key": "value"} 103 104 u, err := db.NewUpload(ctx) 105 if err != nil { 106 t.Fatalf("NewUpload: %v", err) 107 } 108 labels["uploadid"] = u.ID 109 for _, num := range []string{"1", "2"} { 110 labels["num"] = num 111 for _, num2 := range []int{1, 2} { 112 if err := u.InsertRecord(&benchfmt.Result{ 113 Labels: labels, 114 NameLabels: nil, 115 LineNum: 1, 116 Content: fmt.Sprintf("BenchmarkName %d ns/op", num2), 117 }); err != nil { 118 t.Fatalf("InsertRecord: %v", err) 119 } 120 labels = labels.Copy() 121 } 122 } 123 124 if err := u.Commit(); err != nil { 125 t.Fatalf("Commit: %v", err) 126 } 127 128 checkQueryResults(t, db, "key:value", 129 `key: value 130 num: 1 131 uploadid: 19700101.1 132 BenchmarkName 1 ns/op 133 BenchmarkName 2 ns/op 134 num: 2 135 BenchmarkName 1 ns/op 136 BenchmarkName 2 ns/op 137 `) 138 139 labels["num"] = "3" 140 141 for _, uploadid := range []string{u.ID, "new"} { 142 u, err := db.ReplaceUpload(uploadid) 143 if err != nil { 144 t.Fatalf("ReplaceUpload: %v", err) 145 } 146 labels["uploadid"] = u.ID 147 if err := u.InsertRecord(&benchfmt.Result{ 148 Labels: labels, 149 NameLabels: nil, 150 LineNum: 1, 151 Content: "BenchmarkName 3 ns/op", 152 }); err != nil { 153 t.Fatalf("InsertRecord: %v", err) 154 } 155 labels = labels.Copy() 156 157 if err := u.Commit(); err != nil { 158 t.Fatalf("Commit: %v", err) 159 } 160 } 161 162 checkQueryResults(t, db, "key:value", 163 `key: value 164 num: 3 165 uploadid: 19700101.1 166 BenchmarkName 3 ns/op 167 uploadid: new 168 BenchmarkName 3 ns/op 169 `) 170 } 171 172 // TestNewUpload verifies that NewUpload and InsertRecord wrote the correct rows to the database. 173 func TestNewUpload(t *testing.T) { 174 SetNow(time.Unix(0, 0)) 175 defer SetNow(time.Time{}) 176 db, cleanup := dbtest.NewDB(t) 177 defer cleanup() 178 179 u, err := db.NewUpload(context.Background()) 180 if err != nil { 181 t.Fatalf("NewUpload: %v", err) 182 } 183 184 br := benchfmt.NewReader(strings.NewReader(` 185 key: value 186 BenchmarkName 1 ns/op 187 BenchmarkName 2 ns/op 188 `)) 189 for br.Next() { 190 if err := u.InsertRecord(br.Result()); err != nil { 191 t.Fatalf("InsertRecord: %v", err) 192 } 193 } 194 if err := br.Err(); err != nil { 195 t.Fatalf("Err: %v", err) 196 } 197 if err := u.Commit(); err != nil { 198 t.Fatalf("Commit: %v", err) 199 } 200 201 rows, err := DBSQL(db).Query("SELECT UploadId, RecordId, Name, Value FROM RecordLabels") 202 if err != nil { 203 t.Fatalf("sql.Query: %v", err) 204 } 205 defer rows.Close() 206 207 want := map[string]string{ 208 "key": "value", 209 "name": "Name", 210 } 211 212 i := 0 213 214 for rows.Next() { 215 var uploadid string 216 var recordid int64 217 var name, value string 218 219 if err := rows.Scan(&uploadid, &recordid, &name, &value); err != nil { 220 t.Fatalf("rows.Scan: %v", err) 221 } 222 if uploadid != "19700101.1" { 223 t.Errorf("uploadid = %q, want %q", uploadid, "19700101.1") 224 } 225 if recordid != 0 { 226 t.Errorf("recordid = %d, want 0", recordid) 227 } 228 if want[name] != value { 229 t.Errorf("%s = %q, want %q", name, value, want[name]) 230 } 231 i++ 232 } 233 if i != len(want) { 234 t.Errorf("have %d labels, want %d", i, len(want)) 235 } 236 237 if err := rows.Err(); err != nil { 238 t.Errorf("rows.Err: %v", err) 239 } 240 } 241 242 func TestQuery(t *testing.T) { 243 db, cleanup := dbtest.NewDB(t) 244 defer cleanup() 245 246 u, err := db.NewUpload(context.Background()) 247 if err != nil { 248 t.Fatalf("NewUpload: %v", err) 249 } 250 251 var allRecords []int 252 253 for i := 0; i < 1024; i++ { 254 allRecords = append(allRecords, i) 255 r := &benchfmt.Result{Labels: make(map[string]string), NameLabels: make(map[string]string), Content: "BenchmarkName 1 ns/op"} 256 r.Labels["upload"] = u.ID 257 for j := uint(0); j < 10; j++ { 258 r.Labels[fmt.Sprintf("label%d", j)] = fmt.Sprintf("%d", i/(1<<j)) 259 } 260 r.NameLabels["name"] = "Name" 261 if err := u.InsertRecord(r); err != nil { 262 t.Fatalf("InsertRecord: %v", err) 263 } 264 } 265 if err := u.Commit(); err != nil { 266 t.Fatalf("Commit: %v", err) 267 } 268 269 tests := []struct { 270 q string 271 want []int // nil means we want an error 272 }{ 273 {"label0:0", []int{0}}, 274 {"label0:1 label0:1 label0<2 label0>0", []int{1}}, 275 {"label0>0 label0<2 label0:1 label0:1", []int{1}}, 276 {"label0<2 label0<1", []int{0}}, 277 {"label0>1021 label0>1022 label1:511", []int{1023}}, 278 {"label1:0", []int{0, 1}}, 279 {"label0:5 name:Name", []int{5}}, 280 {"label0:0 label0:5", []int{}}, 281 {"bogus query", nil}, 282 {"label1<2 label3:0", []int{0, 1, 2, 3}}, 283 {"label1>510 label1<52", []int{1022, 1023}}, 284 {"", allRecords}, 285 {"missing>", []int{}}, 286 {"label0>", allRecords}, 287 {"upload:" + u.ID, allRecords}, 288 {"upload:none", []int{}}, 289 {"upload>" + u.ID, []int{}}, 290 {"upload<" + u.ID, []int{}}, 291 {"label0:0 upload:" + u.ID, []int{0}}, 292 } 293 for _, test := range tests { 294 t.Run("query="+test.q, func(t *testing.T) { 295 q := db.Query(test.q) 296 if test.want == nil { 297 if q.Next() { 298 t.Fatal("Next() = true, want false") 299 } 300 if err := q.Err(); err == nil { 301 t.Fatal("Err() = nil, want error") 302 } 303 return 304 } 305 defer func() { 306 t.Logf("q.Debug: %s", q.Debug()) 307 if err := q.Close(); err != nil { 308 t.Errorf("Close: %v", err) 309 } 310 }() 311 var have []int 312 for i := range test.want { 313 if !q.Next() { 314 t.Fatalf("#%d: Next() = false", i) 315 } 316 r := q.Result() 317 n, err := strconv.Atoi(r.Labels["label0"]) 318 if err != nil { 319 t.Fatalf("unexpected label0 value %q: %v", r.Labels["label0"], err) 320 } 321 have = append(have, n) 322 if r.NameLabels["name"] != "Name" { 323 t.Errorf("result[%d].name = %q, want %q", i, r.NameLabels["name"], "Name") 324 } 325 } 326 for q.Next() { 327 r := q.Result() 328 t.Errorf("Next() = true, want false (got labels %v)", r.Labels) 329 } 330 if err := q.Err(); err != nil { 331 t.Errorf("Err() = %v, want nil", err) 332 } 333 sort.Ints(have) 334 if len(have) == 0 { 335 have = []int{} 336 } 337 if !reflect.DeepEqual(have, test.want) { 338 t.Errorf("label0[] = %v, want %v", have, test.want) 339 } 340 }) 341 } 342 } 343 344 // TestListUploads verifies that ListUploads returns the correct values. 345 func TestListUploads(t *testing.T) { 346 SetNow(time.Unix(0, 0)) 347 defer SetNow(time.Time{}) 348 db, cleanup := dbtest.NewDB(t) 349 defer cleanup() 350 351 for i := -1; i < 9; i++ { 352 u, err := db.NewUpload(context.Background()) 353 if err != nil { 354 t.Fatalf("NewUpload: %v", err) 355 } 356 for j := 0; j <= i; j++ { 357 labels := benchfmt.Labels{ 358 "key": "value", 359 "i": fmt.Sprintf("%d", i), 360 "j": fmt.Sprintf("%d", j), 361 } 362 if err := u.InsertRecord(&benchfmt.Result{ 363 Labels: labels, 364 NameLabels: nil, 365 LineNum: 1, 366 Content: fmt.Sprintf("BenchmarkName %d ns/op", j), 367 }); err != nil { 368 t.Fatalf("InsertRecord: %v", err) 369 } 370 } 371 if err := u.Commit(); err != nil { 372 t.Fatalf("Commit: %v", err) 373 } 374 } 375 376 type result struct { 377 count int 378 id string 379 } 380 381 tests := []struct { 382 query string 383 extraLabels []string 384 limit int 385 want []result 386 }{ 387 {"", nil, 0, []result{{9, "19700101.10"}, {8, "19700101.9"}, {7, "19700101.8"}, {6, "19700101.7"}, {5, "19700101.6"}, {4, "19700101.5"}, {3, "19700101.4"}, {2, "19700101.3"}, {1, "19700101.2"}}}, 388 {"", nil, 2, []result{{9, "19700101.10"}, {8, "19700101.9"}}}, 389 {"j:5", nil, 0, []result{{1, "19700101.10"}, {1, "19700101.9"}, {1, "19700101.8"}, {1, "19700101.7"}}}, 390 {"i:5", nil, 0, []result{{6, "19700101.7"}}}, 391 {"i:5", []string{"i", "missing"}, 0, []result{{6, "19700101.7"}}}, 392 {"not:found", nil, 0, nil}, 393 } 394 395 for _, test := range tests { 396 t.Run(fmt.Sprintf("query=%s/limit=%d", test.query, test.limit), func(t *testing.T) { 397 r := db.ListUploads(test.query, test.extraLabels, test.limit) 398 defer func() { 399 t.Logf("r.Debug: %s", r.Debug()) 400 r.Close() 401 }() 402 var have []result 403 for r.Next() { 404 ui := r.Info() 405 res := result{ui.Count, ui.UploadID} 406 have = append(have, res) 407 for k, v := range ui.LabelValues { 408 switch k { 409 case "i": 410 uploadNum, err := strconv.Atoi(res.id[strings.LastIndex(res.id, ".")+1:]) 411 if err != nil { 412 t.Fatalf("cannot parse upload ID %q", res.id) 413 } 414 if v != fmt.Sprintf("%d", uploadNum-2) { 415 t.Errorf(`i = %q, want "%d"`, v, uploadNum-2) 416 } 417 default: 418 t.Errorf("unexpected label %q", k) 419 } 420 } 421 } 422 if err := r.Err(); err != nil { 423 t.Errorf("Err() = %v", err) 424 } 425 if !reflect.DeepEqual(have, test.want) { 426 t.Errorf("results = %v, want %v", have, test.want) 427 } 428 }) 429 } 430 }