test: add test cases for overflow and pricision lost

This commit is contained in:
xieyuschen 2024-03-27 18:15:16 +08:00
parent 2c1dac4e8f
commit 3c3df7b2b7
No known key found for this signature in database
GPG Key ID: 4C4189F4DAA5C381
2 changed files with 124 additions and 1 deletions

View File

@ -128,7 +128,7 @@ type counter struct {
//
// note that if a part of addend is added on base but the left causes a rounding error,
// we don't respect this case
func addWithRoundingErrorChecking(base float64, addend float64) (float64, bool) {
func addWithRoundingErrorChecking(base, addend float64) (float64, bool) {
if addend == 0 {
return base, false
}

View File

@ -79,6 +79,114 @@ func TestCounterAdd(t *testing.T) {
}
}
func TestCounterOverflowAdd(t *testing.T) {
now := time.Now()
counter := NewCounter(CounterOpts{
Name: "test",
Help: "test help",
ConstLabels: Labels{"a": "1", "b": "2"},
now: func() time.Time { return now },
}).(*counter)
counter.change = math.MaxUint64
counter.Inc()
// this is expected due to the overflow
if expected, got := uint64(0), counter.change; expected != got {
t.Errorf("Expected %d, got %d.", expected, got)
}
m := &dto.Metric{}
counter.Write(m)
expected := &dto.Metric{
Label: []*dto.LabelPair{
{Name: proto.String("a"), Value: proto.String("1")},
{Name: proto.String("b"), Value: proto.String("2")},
},
Counter: &dto.Counter{
Value: proto.Float64(0),
CreatedTimestamp: timestamppb.New(now),
},
}
if !proto.Equal(expected, m) {
t.Errorf("expected %q, got %q", expected, m)
}
}
func TestCounterPrecisionLosingAdd(t *testing.T) {
now := time.Now()
counter := NewCounter(CounterOpts{
Name: "test",
Help: "test help",
ConstLabels: Labels{"a": "1", "b": "2"},
now: func() time.Time { return now },
}).(*counter)
counter.Add(1 << 53)
if expected, got := float64(1<<53), math.Float64frombits(counter.valBits); expected != got {
t.Errorf("Expected %f, got %f.", expected, got)
}
counter.Inc()
if expected, got := uint64(1), counter.change; expected != got {
t.Errorf("Expected %d, got %d.", expected, got)
}
// along with the value 1 inside change, the sum could be added into the float without losing precision
counter.Add(1)
if expected, got := float64(1<<53+2), math.Float64frombits(counter.valBits); expected != got {
t.Errorf("Expected %f, got %f.", expected, got)
}
// the change is reset to 0
if expected, got := uint64(0), counter.change; expected != got {
t.Errorf("Expected %d, got %d.", expected, got)
}
// the value will flip with 2
counter.Add(1)
if expected, got := float64(1<<53+4), math.Float64frombits(counter.valBits); expected != got {
t.Errorf("Expected %f, got %f.", expected, got)
}
if expected, got := uint64(0), counter.change; expected != got {
t.Errorf("Expected %d, got %d.", expected, got)
}
counter.Add(1)
if expected, got := float64(1<<53+4), math.Float64frombits(counter.valBits); expected != got {
t.Errorf("Expected %f, got %f.", expected, got)
}
if expected, got := uint64(1), counter.change; expected != got {
t.Errorf("Expected %d, got %d.", expected, got)
}
counter.Add(1)
if expected, got := float64(1<<53+6), math.Float64frombits(counter.valBits); expected != got {
t.Errorf("Expected %f, got %f.", expected, got)
}
if expected, got := uint64(0), counter.change; expected != got {
t.Errorf("Expected %d, got %d.", expected, got)
}
m := &dto.Metric{}
counter.Write(m)
expected := &dto.Metric{
Label: []*dto.LabelPair{
{Name: proto.String("a"), Value: proto.String("1")},
{Name: proto.String("b"), Value: proto.String("2")},
},
Counter: &dto.Counter{
Value: proto.Float64(1<<53 + 6),
CreatedTimestamp: timestamppb.New(now),
},
}
if !proto.Equal(expected, m) {
t.Errorf("expected %q, got %q", expected, m)
}
}
func decreaseCounter(c *counter) (err error) {
defer func() {
if e := recover(); e != nil {
@ -418,6 +526,21 @@ func Test_hasRoundingError(t *testing.T) {
wantRoundingError: true,
wantNumber: 1 << 53,
},
{
name: "no rounding error",
base: 1 << 53,
delta: 2,
wantRoundingError: true,
wantNumber: 1<<53 + 2,
},
{
name: "no rounding error",
base: 1<<53 + 2,
delta: 1,
wantRoundingError: false,
// there is a precision losing
wantNumber: 1<<53 + 4,
},
{
name: "rounding error",
base: 1 << 54,