test: add test cases for overflow and pricision lost
This commit is contained in:
parent
2c1dac4e8f
commit
3c3df7b2b7
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue