blob: 352d9d1dd3756ccdf1f0a473f5f43369902160bc [file] [log] [blame]
// Copyright 2020 The Chromium 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 eval
import (
"bytes"
"container/heap"
"fmt"
"strings"
"testing"
"infra/rts"
evalpb "infra/rts/presubmit/eval/proto"
. "github.com/smartystreets/goconvey/convey"
. "go.chromium.org/luci/common/testing/assertions"
)
func TestBucketSlice(t *testing.T) {
t.Parallel()
Convey(`bucketSlice`, t, func() {
Convey(`inc`, func() {
thresholds := make([]*evalpb.Threshold, 10)
for i := 0; i < len(thresholds); i++ {
thresholds[i] = &evalpb.Threshold{
MaxDistance: float32(i),
}
}
b := make(bucketSlice, len(thresholds)+1)
Convey(`2`, func() {
b.inc(thresholds, rts.Affectedness{Distance: 2}, 1)
So(b[2], ShouldEqual, 1)
})
Convey(`3`, func() {
b.inc(thresholds, rts.Affectedness{Distance: 3}, 1)
So(b[3], ShouldEqual, 1)
})
Convey(`10`, func() {
b.inc(thresholds, rts.Affectedness{Distance: 10}, 1)
So(b[10], ShouldEqual, 1)
})
Convey(`0`, func() {
// This data point was not lost by any threshold.
b.inc(thresholds, rts.Affectedness{Distance: 0}, 1)
So(b[0], ShouldEqual, 1)
})
Convey(`11`, func() {
// This data point was lost by all thresholds.
b.inc(thresholds, rts.Affectedness{Distance: 11}, 1)
So(b[10], ShouldEqual, 1)
})
})
Convey(`makeCumulative`, func() {
b := make(bucketSlice, 10)
assert10 := func(expected string) {
expected = strings.TrimPrefix(expected, "\n")
expected = strings.Replace(expected, "\t", "", -1)
var buf bytes.Buffer
for _, v := range b {
fmt.Fprintf(&buf, "%d", v)
}
So(buf.String(), ShouldEqual, expected)
}
Convey(`b[0] = 1`, func() {
b[0] = 1
b.makeCumulative()
assert10(`1000000000`)
})
Convey(`b[5] = 1`, func() {
b[5] = 1
b.makeCumulative()
assert10(`1111110000`)
})
Convey(`b[2] = 1, b[4] = 2`, func() {
b[2] = 1
b[4] = 2
b.makeCumulative()
assert10(`3332200000`)
})
})
})
}
func TestMostAffected(t *testing.T) {
t.Parallel()
Convey(`Test[]rts.Affectedness`, t, func() {
Convey(`mostAffected`, func() {
Convey(`Works`, func() {
most, err := mostAffected([]rts.Affectedness{
{Distance: 1},
{Distance: 0},
})
So(err, ShouldBeNil)
So(most, ShouldResemble, rts.Affectedness{Distance: 0})
})
Convey(`Empty`, func() {
_, err := mostAffected(nil)
So(err, ShouldErrLike, "empty")
})
Convey(`Single`, func() {
most, err := mostAffected([]rts.Affectedness{{Distance: 0}})
So(err, ShouldBeNil)
So(most, ShouldResemble, rts.Affectedness{Distance: 0})
})
})
})
}
func TestQuantiles(t *testing.T) {
t.Parallel()
Convey(`Quantiles`, t, func() {
Convey(`median of 1, 2, 3, 4`, func() {
afs := []rts.Affectedness{
{Distance: 1},
{Distance: 2},
{Distance: 3},
{Distance: 4},
}
So(distanceQuantiles(afs, 2), ShouldResemble, []float32{2, 4})
})
Convey(`4-quantiles of 1, 2, 3, 4`, func() {
afs := []rts.Affectedness{
{Distance: 1},
{Distance: 2},
{Distance: 3},
{Distance: 4},
}
So(distanceQuantiles(afs, 4), ShouldResemble, []float32{1, 2, 3, 4})
})
Convey(`10-quantiles of 1, 2, 3, 4`, func() {
afs := []rts.Affectedness{
{Distance: 1},
{Distance: 2},
{Distance: 3},
{Distance: 4},
}
So(distanceQuantiles(afs, 10), ShouldResemble, []float32{1, 1, 2, 2, 2, 3, 3, 4, 4, 4})
})
})
}
func TestFurthestRejections(t *testing.T) {
Convey("FurthestRejections", t, func() {
furthest := make(furthestRejections, 3)
furthest.Consider(affectedRejection{MostAffected: rts.Affectedness{Distance: 1}})
furthest.Consider(affectedRejection{MostAffected: rts.Affectedness{Distance: 2}})
furthest.Consider(affectedRejection{MostAffected: rts.Affectedness{Distance: 3}})
furthest.Consider(affectedRejection{MostAffected: rts.Affectedness{Distance: 4}})
furthest.Consider(affectedRejection{MostAffected: rts.Affectedness{Distance: 5}})
So(len(furthest), ShouldEqual, 3)
So(heap.Pop(&furthest), ShouldResemble, affectedRejection{MostAffected: rts.Affectedness{Distance: 3}})
So(heap.Pop(&furthest), ShouldResemble, affectedRejection{MostAffected: rts.Affectedness{Distance: 4}})
So(heap.Pop(&furthest), ShouldResemble, affectedRejection{MostAffected: rts.Affectedness{Distance: 5}})
})
}