119 lines
3.0 KiB
Go
119 lines
3.0 KiB
Go
|
// Copyright 2021 The Prometheus Authors
|
||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
// you may not use this file except in compliance with the License.
|
||
|
// You may obtain a copy of the License at
|
||
|
//
|
||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||
|
//
|
||
|
// Unless required by applicable law or agreed to in writing, software
|
||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
// See the License for the specific language governing permissions and
|
||
|
// limitations under the License.
|
||
|
|
||
|
//go:build !go1.17
|
||
|
// +build !go1.17
|
||
|
|
||
|
package prometheus
|
||
|
|
||
|
import (
|
||
|
"runtime"
|
||
|
"testing"
|
||
|
"time"
|
||
|
|
||
|
dto "github.com/prometheus/client_model/go"
|
||
|
)
|
||
|
|
||
|
func TestGoCollectorMemStats(t *testing.T) {
|
||
|
var (
|
||
|
c = NewGoCollector().(*goCollector)
|
||
|
got uint64
|
||
|
)
|
||
|
|
||
|
checkCollect := func(want uint64) {
|
||
|
metricCh := make(chan Metric)
|
||
|
endCh := make(chan struct{})
|
||
|
|
||
|
go func() {
|
||
|
c.Collect(metricCh)
|
||
|
close(endCh)
|
||
|
}()
|
||
|
Collect:
|
||
|
for {
|
||
|
select {
|
||
|
case metric := <-metricCh:
|
||
|
if metric.Desc().fqName != "go_memstats_alloc_bytes" {
|
||
|
continue Collect
|
||
|
}
|
||
|
pb := &dto.Metric{}
|
||
|
metric.Write(pb)
|
||
|
got = uint64(pb.GetGauge().GetValue())
|
||
|
case <-endCh:
|
||
|
break Collect
|
||
|
}
|
||
|
}
|
||
|
if want != got {
|
||
|
t.Errorf("unexpected value of go_memstats_alloc_bytes, want %d, got %d", want, got)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// Speed up the timing to make the test faster.
|
||
|
c.msMaxWait = 5 * time.Millisecond
|
||
|
c.msMaxAge = 50 * time.Millisecond
|
||
|
|
||
|
// Scenario 1: msRead responds slowly, no previous memstats available,
|
||
|
// msRead is executed anyway.
|
||
|
c.msRead = func(ms *runtime.MemStats) {
|
||
|
time.Sleep(20 * time.Millisecond)
|
||
|
ms.Alloc = 1
|
||
|
}
|
||
|
checkCollect(1)
|
||
|
// Now msLast is set.
|
||
|
c.msMtx.Lock()
|
||
|
if want, got := uint64(1), c.msLast.Alloc; want != got {
|
||
|
t.Errorf("unexpected of msLast.Alloc, want %d, got %d", want, got)
|
||
|
}
|
||
|
c.msMtx.Unlock()
|
||
|
|
||
|
// Scenario 2: msRead responds fast, previous memstats available, new
|
||
|
// value collected.
|
||
|
c.msRead = func(ms *runtime.MemStats) {
|
||
|
ms.Alloc = 2
|
||
|
}
|
||
|
checkCollect(2)
|
||
|
// msLast is set, too.
|
||
|
c.msMtx.Lock()
|
||
|
if want, got := uint64(2), c.msLast.Alloc; want != got {
|
||
|
t.Errorf("unexpected of msLast.Alloc, want %d, got %d", want, got)
|
||
|
}
|
||
|
c.msMtx.Unlock()
|
||
|
|
||
|
// Scenario 3: msRead responds slowly, previous memstats available, old
|
||
|
// value collected.
|
||
|
c.msRead = func(ms *runtime.MemStats) {
|
||
|
time.Sleep(20 * time.Millisecond)
|
||
|
ms.Alloc = 3
|
||
|
}
|
||
|
checkCollect(2)
|
||
|
// After waiting, new value is still set in msLast.
|
||
|
time.Sleep(80 * time.Millisecond)
|
||
|
c.msMtx.Lock()
|
||
|
if want, got := uint64(3), c.msLast.Alloc; want != got {
|
||
|
t.Errorf("unexpected of msLast.Alloc, want %d, got %d", want, got)
|
||
|
}
|
||
|
c.msMtx.Unlock()
|
||
|
|
||
|
// Scenario 4: msRead responds slowly, previous memstats is too old, new
|
||
|
// value collected.
|
||
|
c.msRead = func(ms *runtime.MemStats) {
|
||
|
time.Sleep(20 * time.Millisecond)
|
||
|
ms.Alloc = 4
|
||
|
}
|
||
|
checkCollect(4)
|
||
|
c.msMtx.Lock()
|
||
|
if want, got := uint64(4), c.msLast.Alloc; want != got {
|
||
|
t.Errorf("unexpected of msLast.Alloc, want %d, got %d", want, got)
|
||
|
}
|
||
|
c.msMtx.Unlock()
|
||
|
}
|