gotest.tools/gotestsum@v1.11.0/cmd/tool/matrix/matrix_test.go (about)

     1  package matrix
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/json"
     6  	"io"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"testing"
    11  	"time"
    12  
    13  	"gotest.tools/gotestsum/testjson"
    14  	"gotest.tools/v3/assert"
    15  	"gotest.tools/v3/fs"
    16  )
    17  
    18  func TestPackagePercentile(t *testing.T) {
    19  	ms := time.Millisecond
    20  	timing := map[string][]time.Duration{
    21  		"none":  {},
    22  		"one":   {time.Second},
    23  		"two":   {4 * ms, 2 * ms},
    24  		"three": {2 * ms, 3 * ms, 5 * ms},
    25  		"four":  {4 * ms, 3 * ms, ms, 2 * ms},
    26  		"five":  {6 * ms, 2 * ms, 3 * ms, 4 * ms, 9 * ms},
    27  		"nine":  {6 * ms, 2 * ms, 3 * ms, 4 * ms, 9 * ms, 1 * ms, 5 * ms, 7 * ms, 8 * ms},
    28  		"ten":   {6 * ms, 2 * ms, 3 * ms, 4 * ms, 9 * ms, 5 * ms, 7 * ms, 8 * ms, ms, ms},
    29  		"twenty": {
    30  			6 * ms, 2 * ms, 3 * ms, 4 * ms, 9 * ms, 5 * ms, 7 * ms, 8 * ms, ms, ms,
    31  			100, 200, 600, 700, 800, 900, 200, 300, 400, 500,
    32  		},
    33  	}
    34  
    35  	out := packagePercentile(timing)
    36  	expected := map[string]time.Duration{
    37  		"none":   0,
    38  		"one":    time.Second,
    39  		"two":    4 * ms,
    40  		"three":  5 * ms,
    41  		"four":   4 * ms,
    42  		"five":   9 * ms,
    43  		"nine":   8 * ms,
    44  		"ten":    8 * ms,
    45  		"twenty": 6 * ms,
    46  	}
    47  	assert.DeepEqual(t, out, expected)
    48  }
    49  
    50  func TestBucketPackages(t *testing.T) {
    51  	ms := time.Millisecond
    52  	timing := map[string]time.Duration{
    53  		"one":   190 * ms,
    54  		"two":   200 * ms,
    55  		"three": 3800 * ms,
    56  		"four":  4000 * ms,
    57  		"five":  50 * ms,
    58  		"six":   606 * ms,
    59  		"rm1":   time.Second,
    60  		"rm2":   time.Second,
    61  	}
    62  	packages := []string{"new1", "new2", "one", "two", "three", "four", "five", "six"}
    63  
    64  	type testCase struct {
    65  		n        uint
    66  		expected []bucket
    67  	}
    68  
    69  	run := func(t *testing.T, tc testCase) {
    70  		buckets := bucketPackages(timing, packages, tc.n)
    71  		assert.DeepEqual(t, buckets, tc.expected)
    72  	}
    73  
    74  	testCases := []testCase{
    75  		{
    76  			n: 2,
    77  			expected: []bucket{
    78  				0: {Total: 4440 * ms, Packages: []string{"four", "two", "one", "five"}},
    79  				1: {Total: 4406 * ms, Packages: []string{"three", "six", "new2", "new1"}},
    80  			},
    81  		},
    82  		{
    83  			n: 3,
    84  			expected: []bucket{
    85  				0: {Total: 4000 * ms, Packages: []string{"four"}},
    86  				1: {Total: 3800 * ms, Packages: []string{"three"}},
    87  				2: {Total: 1046 * ms, Packages: []string{"six", "two", "one", "five", "new1", "new2"}},
    88  			},
    89  		},
    90  		{
    91  			n: 4,
    92  			expected: []bucket{
    93  				0: {Total: 4000 * ms, Packages: []string{"four"}},
    94  				1: {Total: 3800 * ms, Packages: []string{"three"}},
    95  				2: {Total: 606 * ms, Packages: []string{"six"}},
    96  				3: {Total: 440 * ms, Packages: []string{"two", "one", "five", "new2", "new1"}},
    97  			},
    98  		},
    99  		{
   100  			n: 8,
   101  			expected: []bucket{
   102  				0: {Total: 4000 * ms, Packages: []string{"four"}},
   103  				1: {Total: 3800 * ms, Packages: []string{"three"}},
   104  				2: {Total: 606 * ms, Packages: []string{"six"}},
   105  				3: {Total: 200 * ms, Packages: []string{"two"}},
   106  				4: {Total: 190 * ms, Packages: []string{"one"}},
   107  				5: {Total: 50 * ms, Packages: []string{"five"}},
   108  				6: {Packages: []string{"new1"}},
   109  				7: {Packages: []string{"new2"}},
   110  			},
   111  		},
   112  	}
   113  
   114  	for _, tc := range testCases {
   115  		t.Run(strconv.FormatUint(uint64(tc.n), 10), func(t *testing.T) {
   116  			run(t, tc)
   117  		})
   118  	}
   119  }
   120  
   121  func TestReadTimingReports(t *testing.T) {
   122  	events := func(t *testing.T, start time.Time) string {
   123  		t.Helper()
   124  		var buf bytes.Buffer
   125  		encoder := json.NewEncoder(&buf)
   126  		for _, i := range []int{0, 1, 2} {
   127  			assert.NilError(t, encoder.Encode(testjson.TestEvent{
   128  				Time:    start.Add(time.Duration(i) * time.Second),
   129  				Action:  testjson.ActionRun,
   130  				Package: "pkg" + strconv.Itoa(i),
   131  			}))
   132  		}
   133  		return buf.String()
   134  	}
   135  
   136  	now := time.Now()
   137  	dir := fs.NewDir(t, "timing-files",
   138  		fs.WithFile("report1.log", events(t, now.Add(-time.Hour))),
   139  		fs.WithFile("report2.log", events(t, now.Add(-47*time.Hour))),
   140  		fs.WithFile("report3.log", events(t, now.Add(-49*time.Hour))),
   141  		fs.WithFile("report4.log", events(t, now.Add(-101*time.Hour))))
   142  
   143  	t.Run("match files", func(t *testing.T) {
   144  		opts := options{
   145  			timingFilesPattern: dir.Join("*.log"),
   146  		}
   147  
   148  		files, err := readTimingReports(opts)
   149  		assert.NilError(t, err)
   150  		defer closeFiles(files)
   151  		assert.Equal(t, len(files), 4)
   152  
   153  		for _, fh := range files {
   154  			// check the files are properly seeked to 0
   155  			event, err := parseEvent(fh)
   156  			assert.NilError(t, err)
   157  			assert.Equal(t, event.Package, "pkg0")
   158  		}
   159  
   160  		actual, err := os.ReadDir(dir.Path())
   161  		assert.NilError(t, err)
   162  		assert.Equal(t, len(actual), 4)
   163  	})
   164  
   165  	t.Run("no glob match, func", func(t *testing.T) {
   166  		opts := options{
   167  			timingFilesPattern: dir.Join("*.json"),
   168  		}
   169  
   170  		files, err := readTimingReports(opts)
   171  		assert.NilError(t, err)
   172  		assert.Equal(t, len(files), 0)
   173  	})
   174  }
   175  
   176  func TestRun(t *testing.T) {
   177  	events := func(t *testing.T) string {
   178  		t.Helper()
   179  		var buf bytes.Buffer
   180  		encoder := json.NewEncoder(&buf)
   181  		for _, i := range []int{0, 1, 2} {
   182  			elapsed := time.Duration(i+1) * 2 * time.Second
   183  			end := time.Now().Add(-5 * time.Second)
   184  			start := end.Add(-elapsed)
   185  
   186  			assert.NilError(t, encoder.Encode(testjson.TestEvent{
   187  				Time:    start,
   188  				Action:  testjson.ActionRun,
   189  				Package: "pkg" + strconv.Itoa(i),
   190  			}))
   191  			assert.NilError(t, encoder.Encode(testjson.TestEvent{
   192  				Time:    end,
   193  				Action:  testjson.ActionPass,
   194  				Package: "pkg" + strconv.Itoa(i),
   195  				Elapsed: elapsed.Seconds(),
   196  			}))
   197  		}
   198  		return buf.String()
   199  	}
   200  
   201  	dir := fs.NewDir(t, "timing-files",
   202  		fs.WithFile("report1.log", events(t)),
   203  		fs.WithFile("report2.log", events(t)),
   204  		fs.WithFile("report3.log", events(t)),
   205  		fs.WithFile("report4.log", events(t)),
   206  		fs.WithFile("report5.log", events(t)))
   207  
   208  	stdout := new(bytes.Buffer)
   209  	opts := options{
   210  		numPartitions:      3,
   211  		timingFilesPattern: dir.Join("*.log"),
   212  		debug:              true,
   213  		stdout:             stdout,
   214  		stdin:              strings.NewReader("pkg0\npkg1\npkg2\nother"),
   215  	}
   216  	err := run(opts)
   217  	assert.NilError(t, err)
   218  	assert.Equal(t, strings.Count(stdout.String(), "\n"), 1,
   219  		"the output should be a single line")
   220  
   221  	assert.Equal(t, formatJSON(t, stdout), expectedMatrix)
   222  }
   223  
   224  // expectedMatrix can be automatically updated by running tests with -update
   225  // nolint:lll
   226  var expectedMatrix = `{
   227    "include": [
   228      {
   229        "description": "0 - pkg2",
   230        "estimatedRuntime": "6s",
   231        "id": 0,
   232        "packages": "pkg2"
   233      },
   234      {
   235        "description": "1 - pkg1",
   236        "estimatedRuntime": "4s",
   237        "id": 1,
   238        "packages": "pkg1"
   239      },
   240      {
   241        "description": "2 - pkg0 and 1 others",
   242        "estimatedRuntime": "2s",
   243        "id": 2,
   244        "packages": "pkg0 other"
   245      }
   246    ]
   247  }`
   248  
   249  func formatJSON(t *testing.T, v io.Reader) string {
   250  	t.Helper()
   251  	raw := map[string]interface{}{}
   252  	err := json.NewDecoder(v).Decode(&raw)
   253  	assert.NilError(t, err)
   254  
   255  	formatted, err := json.MarshalIndent(raw, "", "  ")
   256  	assert.NilError(t, err)
   257  	return string(formatted)
   258  }