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