Skip to main content

[go] Viết test code prometheus xem delta và rate tính thế nào

Bài trước đã dùng mắt để chạy code funcDeltafuncRate 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 funcDeltafuncRate đề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: delta

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

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.

yagi

Comments

Popular posts from this blog

Tài liệu và hướng dẫn học Python

Để tiết kiệm thời gian, tốt nhất là đi học PyMI Updated: 130617 Sau đây là các tài liệu khuyên dùng: Vì nhiều lý do, nên học python2.7 tại thời điểm hiện tại (giờ là tháng 6/2013 - muốn biết tại sao thì tự tìm hiểu) python 3.5+ (giờ là tháng 2/2017) Chuẩn bị: 1. biết bật tắt máy 2. biết cài python 3. tập gõ 10 ngón - gõ 2 ngón hay 1 ngón cũng không sao, nhưng 10 ngón là cách dễ nhất để gõ nhanh nhất. Tài liệu - Nên dùng tài liệu tại trang chủ của Python làm chính, tham khảo thêm các tài liệu khác tại http://www.familug.org/2016/12/free-ebook.html Căn bản, mới học 1.1 Python PyMI.vn https://pymi.vn/tutorial/ 1.2. Python offical tutorial kết hợp làm bài tập trên HackerRank  (đề bài bằng tiếng Anh, nhưng Google translate 1 lúc cũng ra vì có nhiều ví dụ mẫu đi kèm). Học viên của Pymi.vn có rất nhiều học viên đã tự học với Learn Python the hard way nhưng chưa thấy ai thành công cả. Hai link dưới nên đọc sau khi đã nắm được những phần cơ bản của ngôn ngữ pytho...

The PyMiers

New FAMILUG