blob: d257bb3d1ecd8bd0c7b93ac3f24139e80e0b124a [file] [log] [blame]
// Copyright 2022 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package main
import (
"errors"
"flag"
"fmt"
"os"
"os/exec"
"strings"
"testing"
"time"
"github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts"
)
var (
updateGoldens = flag.Bool("update-goldens", false, "Whether to update goldens")
)
func TestUpdate(t *testing.T) {
t.Parallel()
newData := []test{
{
Name: "still_existing_test",
Builder: "foo",
MedianDurationMS: 10,
Runs: 3,
},
{
Name: "still_existing_test",
Builder: "new-builder",
MedianDurationMS: 100,
Runs: 12,
},
{
Name: "new_test",
Builder: "foo",
MedianDurationMS: 12,
Runs: 4,
},
}
goldensDir := "testdata/goldens"
var outputDir string
if *updateGoldens {
// Clear the goldens directory to garbage-collect old files.
if err := os.RemoveAll(goldensDir); err != nil {
t.Fatal(err)
}
if err := os.MkdirAll(goldensDir, 0o700); err != nil {
t.Fatal(err)
}
outputDir = goldensDir
} else {
outputDir = t.TempDir()
}
now := time.Date(2023, 11, 23, 0, 0, 0, 0, time.UTC)
if err := update(newData, "testdata/old_durations", outputDir, true, now); err != nil {
t.Fatalf("Unexpected error: %s", err)
}
// We directly wrote the files to the goldens directory, so we know they'll
// be up-to-date, no point in checking them.
if *updateGoldens {
return
}
cmd := exec.Command(
"git", "diff", "--no-index", "--no-ext-diff", "--no-prefix",
goldensDir, outputDir,
)
var stdout, stderr strings.Builder
cmd.Stdout = &stdout
cmd.Stderr = &stderr
err := cmd.Run()
var errExit *exec.ExitError
if errors.As(err, &errExit) && errExit.ExitCode() == 1 {
t.Fatalf(
"Unexpected diff: %s\n\n"+
"To update goldens, run: `go test ./cmd/update_test_durations -update-goldens`",
stdout.String())
} else if err != nil {
t.Fatalf("Error running git diff: %s", err)
}
}
func TestCalculateDefaultDurations(t *testing.T) {
t.Parallel()
durations := testDurationMap{
"bar": append(
testsWithDurations("bar", 3),
test{Name: "shared", Runs: 2, MedianDurationMS: 20}),
"foo": append(
testsWithDurations("foo", 1),
test{Name: "shared", Runs: 1, MedianDurationMS: 5}),
}
got, err := calculateDefaultDurations(durations)
if err != nil {
t.Fatal(err)
}
want := appendAll(
testsWithDurations("bar", 3),
testsWithDurations("foo", 1),
[]test{
{
Name: "shared",
Runs: 3,
MedianDurationMS: 15,
},
})
if diff := cmp.Diff(want, got, cmpopts.IgnoreFields(test{}, "Builder")); diff != "" {
t.Errorf("Unexpected diff:\n%s", diff)
}
}
// testsWithDurations constructs a slice of tests with the given durations, in
// order, all have the same builder.
func testsWithDurations(builder string, durations ...int64) []test {
var res []test
for i, duration := range durations {
res = append(res, test{
Name: fmt.Sprintf("%s-%d", builder, i),
Builder: builder,
MedianDurationMS: duration,
Runs: 1,
})
}
return res
}
func appendAll(slices ...[]test) []test {
var res []test
for _, s := range slices {
res = append(res, s...)
}
return res
}