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  }