blob: c3fad3d1e86733b9c52d3ff1f31516498a56321f [file] [log] [blame]
// Copyright 2019 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 testsharder
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"reflect"
"sort"
"strings"
"testing"
"go.fuchsia.dev/fuchsia/tools/build"
)
var barTestModifier = TestModifier{
Name: "bar_tests",
TotalRuns: 2,
}
var bazTestModifier = TestModifier{
Name: "baz_host_tests",
OS: linux,
}
func TestLoadTestModifiers(t *testing.T) {
areEqual := func(a, b []TestModifier) bool {
stringify := func(modifier TestModifier) string {
return fmt.Sprintf("%#v", modifier)
}
sort := func(list []TestModifier) {
sort.Slice(list[:], func(i, j int) bool {
return stringify(list[i]) < stringify(list[j])
})
}
sort(a)
sort(b)
return reflect.DeepEqual(a, b)
}
tmpDir, err := ioutil.TempDir("", "test-spec")
if err != nil {
t.Fatalf("failed to create temp dir: %v", err)
}
defer os.RemoveAll(tmpDir)
initial := []TestModifier{barTestModifier, bazTestModifier}
modifiersPath := filepath.Join(tmpDir, "test_modifiers.json")
m, err := os.Create(modifiersPath)
if err != nil {
t.Fatal(err)
}
defer m.Close()
if err := json.NewEncoder(m).Encode(&initial); err != nil {
t.Fatal(err)
}
actual, err := LoadTestModifiers(modifiersPath)
if err != nil {
t.Fatalf("failed to load test modifiers: %v", err)
}
bazOut := bazTestModifier
barOut := barTestModifier
barOut.OS = ""
expected := []TestModifier{barOut, bazOut}
if !areEqual(expected, actual) {
t.Fatalf("test modifiers not properly loaded:\nexpected:\n%+v\nactual:\n%+v", expected, actual)
}
}
func TestAffectedModifiers(t *testing.T) {
affectedTestsFile, err := ioutil.TempFile("", "")
if err != nil {
t.Fatalf("ioutil.TempFile() failed: %v", err)
}
defer func() {
if err := affectedTestsFile.Close(); err != nil {
t.Errorf("affectedTestsFile.Close() failed: %v", err)
}
if err := os.Remove(affectedTestsFile.Name()); err != nil {
t.Errorf("os.Remove(affectedTestsFile) failed: %v", err)
}
}()
affectedTests := []string{
"affected-arm64", "affected-linux", "affected-mac", "affected-host+target", "affected-AEMU", "affected-other-device",
}
_, err = affectedTestsFile.Write([]byte(strings.Join(affectedTests, "\n")))
if err != nil {
t.Fatalf("affectedTestsFile.Write() failed: %v", err)
}
const maxAttempts = 2
t.Run("not multiplied if over threshold", func(t *testing.T) {
mods, err := AffectedModifiers(nil, affectedTestsFile.Name(), maxAttempts, len(affectedTests)-1)
if err != nil {
t.Errorf("AffectedModifiers() returned failed: %v", err)
}
for _, mod := range mods {
if mod.MaxAttempts != maxAttempts {
t.Errorf("%s.MaxAttempts is %d, want %d", mod.Name, mod.MaxAttempts, maxAttempts)
}
if !mod.Affected {
t.Errorf("%s.Affected is false, want true", mod.Name)
}
if mod.TotalRuns >= 0 {
t.Errorf("%s.TotalRuns is %d, want -1", mod.Name, mod.TotalRuns)
}
}
})
t.Run("multiplied", func(t *testing.T) {
specs := []build.TestSpec{
{Test: build.Test{Name: "affected-arm64", OS: linux, CPU: "arm64"}},
{Test: build.Test{Name: "affected-linux", OS: linux, CPU: x64}},
{Test: build.Test{Name: "affected-mac", OS: "mac", CPU: x64}},
{Test: build.Test{Name: "affected-host+target", OS: linux, CPU: x64},
Envs: []build.Environment{{Dimensions: build.DimensionSet{DeviceType: "AEMU"}}}},
{Test: build.Test{Name: "affected-AEMU", OS: fuchsia, CPU: x64},
Envs: []build.Environment{{Dimensions: build.DimensionSet{DeviceType: "AEMU"}}}},
{Test: build.Test{Name: "affected-other-device", OS: fuchsia, CPU: x64},
Envs: []build.Environment{{Dimensions: build.DimensionSet{DeviceType: "other-device"}}}},
{Test: build.Test{Name: "not-affected"}},
}
nameToShouldBeMultiplied := map[string]bool{
"affected-arm64": false,
"affected-linux": true,
"affected-mac": false,
"affected-host+target": false,
"affected-AEMU": true,
"affected-other-device": false,
}
mods, err := AffectedModifiers(specs, affectedTestsFile.Name(), maxAttempts, len(affectedTests))
if err != nil {
t.Errorf("AffectedModifiers() returned failed: %v", err)
}
for _, mod := range mods {
shouldBeMultiplied := nameToShouldBeMultiplied[mod.Name]
if shouldBeMultiplied {
if mod.MaxAttempts != 0 {
t.Errorf("%s.MaxAttempts is %d, want 0", mod.Name, mod.MaxAttempts)
}
if mod.TotalRuns != 0 {
t.Errorf("%s.TotalRuns is %d, want 0", mod.Name, mod.MaxAttempts)
}
} else {
if mod.MaxAttempts != maxAttempts {
t.Errorf("%s.MaxAttempts is %d, want %d", mod.Name, mod.MaxAttempts, maxAttempts)
}
if !mod.Affected {
t.Errorf("%s.Affected is false, want true", mod.Name)
}
if mod.TotalRuns >= 0 {
t.Errorf("%s.TotalRuns is %d, want -1", mod.Name, mod.TotalRuns)
}
}
}
})
}