Bài trước đã dùng mắt để chạy code funcDelta
và funcRate
của Prometheus để xem code chạy qua những dòng nào, những phép tính nào được tính trong extrapolatedRate
.
Bài này sẽ sử dụng go test coverage để xem code nào được chạy.
Viết test Prometheus
Code của funcDelta
và funcRate
đều nằm trong file promql/functions.go
, theo quy ước chung của Go, test sẽ nằm trong promql/functions_test.go
, nhưng file này chỉ chứa có 2 test:
$ grep ^func -c functions*_test.go
functions_internal_test.go:1
functions_test.go:2
Lý do là PromQL tự tạo ra 1 kiểu/ngôn ngữ test riêng cho ngôn ngữ PromQL, nằm trong thư mục promqltest/
chứ không phải Golang test thông thường. file promqltest/README.md
viết:
The PromQL test scripting language
This package contains two things:
- an implementation of a test scripting language for PromQL engines
- a predefined set of tests written in that scripting language
$ find promql/promqltest
promql/promqltest
promql/promqltest/README.md
promql/promqltest/testdata
promql/promqltest/testdata/aggregators.test
promql/promqltest/testdata/at_modifier.test
promql/promqltest/testdata/collision.test
promql/promqltest/testdata/literals.test
promql/promqltest/testdata/selectors.test
promql/promqltest/testdata/staleness.test
promql/promqltest/testdata/trig_functions.test
promql/promqltest/testdata/range_queries.test
promql/promqltest/testdata/functions.test
promql/promqltest/testdata/native_histograms.test
promql/promqltest/testdata/operators.test
promql/promqltest/testdata/limit.test
promql/promqltest/testdata/histograms.test
promql/promqltest/testdata/subquery.test
promql/promqltest/test.go
promql/promqltest/test_test.go
may thay, trong functions_test
vẫn có 1 function, và 1 là đủ để làm ví dụ rồi:
func TestDeriv(t *testing.T) {
// https://github.com/prometheus/prometheus/issues/2674#issuecomment-315439393
// This requires more precision than the usual test system offers,
// so we test it by hand.
Copy function này, tạo function để test funcDelta:
func TestDelta(t *testing.T) {
storage := teststorage.New(t)
defer storage.Close()
opts := promql.EngineOpts{
Logger: nil,
Reg: nil,
MaxSamples: 10000,
Timeout: 10 * time.Second,
}
engine := promql.NewEngine(opts)
a := storage.Appender(context.Background())
metric := labels.FromStrings("__name__", "foo")
a.Append(0, metric, 1726745659174, 120)
a.Append(0, metric, 1726745674174, 122)
a.Append(0, metric, 1726745689174, 134)
a.Append(0, metric, 1726745704174, 149)
require.NoError(t, a.Commit())
ctx := context.Background()
query, err := engine.NewInstantQuery(ctx, storage, nil, "delta(foo[1m])", timestamp.Time(1726745705174))
require.NoError(t, err)
result := query.Exec(ctx)
require.NoError(t, result.Err)
vec, _ := result.Vector()
require.Len(t, vec, 1, "Expected 1 result, got %d", len(vec))
require.Equal(t, 0.0, vec[0].F, "Expected 0.0 as value, got %f", vec[0].F)
}
Chạy test tạo coverprofile
$ go test -run TestDelta -coverprofile=coverage.delta
--- FAIL: TestDelta (0.01s)
functions_test.go:61:
Error Trace: ~/prometheus/promql/functions_test.go:61
Error: Not equal:
expected: 0
actual : 38.666666666666664
Test: TestDelta
Messages: Expected 0.0 as value, got 38.666667
FAIL
coverage: 14.5% of statements
exit status 1
FAIL github.com/prometheus/prometheus/promql 0.023s
$ go tool cover -html=coverage.delta
File này chỉ là 1 file text với nội dung
mode: set
github.com/prometheus/prometheus/promql/engine.go:86.41,88.2 1 0
github.com/prometheus/prometheus/promql/engine.go:102.41,104.2 1 0
github.com/prometheus/prometheus/promql/engine.go:106.42,108.2 1 0
github.com/prometheus/prometheus/promql/engine.go:110.43,112.2 1 0
...
github.com/prometheus/prometheus/promql/functions.go:61.116,65.2 1 0
github.com/prometheus/prometheus/promql/functions.go:71.148,89.60 5 1
github.com/prometheus/prometheus/promql/functions.go:89.60,91.3 1 0
...
mở trình duyệt với hình:
Tương tự để test rate:
func TestRate(t *testing.T) {
storage := teststorage.New(t)
defer storage.Close()
opts := promql.EngineOpts{
Logger: nil,
Reg: nil,
MaxSamples: 10000,
Timeout: 10 * time.Second,
}
engine := promql.NewEngine(opts)
a := storage.Appender(context.Background())
metric := labels.FromStrings("__name__", "foo")
a.Append(0, metric, 1726745659174, 120)
a.Append(0, metric, 1726745674174, 122)
a.Append(0, metric, 1726745689174, 134)
a.Append(0, metric, 1726745704174, 149)
require.NoError(t, a.Commit())
ctx := context.Background()
query, err := engine.NewInstantQuery(ctx, storage, nil, "rate(foo[1m])", timestamp.Time(1726745705174))
require.NoError(t, err)
result := query.Exec(ctx)
require.NoError(t, result.Err)
vec, _ := result.Vector()
require.Len(t, vec, 1, "Expected 1 result, got %d", len(vec))
require.Equal(t, 0.0, vec[0].F, "Expected 0.0 as value, got %f", vec[0].F)
}
Chạy
$ go test -run TestRate -coverprofile=coverage.rate
--- FAIL: TestRate (0.01s)
functions_test.go:61:
Error Trace: /home/hvn/code/prometheus/promql/functions_test.go:61
Error: Not equal:
expected: 0
actual : 0.6444444444444444
Test: TestRate
Messages: Expected 0.0 as value, got 0.644444
FAIL
coverage: 14.9% of statements
exit status 1
FAIL github.com/prometheus/prometheus/promql 0.021s
$ go tool cover -html=coverage.rate
Kết luận
Prometheus function không tính sai, nó chỉ tính đúng như trong tài liệu mô tả. Hãy đọc tài liệu. Hoặc đọc code.
Hết.
HVN at http://pymi.vn and https://www.familug.org.
Ủng hộ đồng bào bị ảnh hưởng bởi cơn bão số 3.
Báo Tuổi Trẻ, Ngân hàng Công thương chi nhánh 3, TP.HCM. Số tài khoản: 113000006100 (Việt Nam đồng). Nội dung: Ủng hộ đồng bào bị ảnh hưởng bởi cơn bão số 3.