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  }