mirror of
https://github.com/SigNoz/signoz.git
synced 2025-12-17 15:36:48 +00:00
231 lines
5.8 KiB
Go
231 lines
5.8 KiB
Go
package querier
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
qbtypes "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
|
|
)
|
|
|
|
func TestPrepareFillZeroArgsWithStep(t *testing.T) {
|
|
q := &querier{}
|
|
|
|
req := &qbtypes.QueryRangeRequest{
|
|
Start: 1000000,
|
|
End: 2000000,
|
|
}
|
|
|
|
tests := []struct {
|
|
name string
|
|
functions []qbtypes.Function
|
|
step int64
|
|
checkArgs bool
|
|
}{
|
|
{
|
|
name: "fillZero without args",
|
|
functions: []qbtypes.Function{
|
|
{
|
|
Name: qbtypes.FunctionNameFillZero,
|
|
Args: []qbtypes.FunctionArg{},
|
|
},
|
|
},
|
|
step: 30000, // 30 seconds
|
|
checkArgs: true,
|
|
},
|
|
{
|
|
name: "fillZero with existing args",
|
|
functions: []qbtypes.Function{
|
|
{
|
|
Name: qbtypes.FunctionNameFillZero,
|
|
Args: []qbtypes.FunctionArg{
|
|
{Value: 500000.0},
|
|
{Value: 1500000.0},
|
|
{Value: 15000.0},
|
|
},
|
|
},
|
|
},
|
|
step: 60000,
|
|
checkArgs: false, // Should not modify existing args
|
|
},
|
|
{
|
|
name: "other function should not be modified",
|
|
functions: []qbtypes.Function{
|
|
{
|
|
Name: qbtypes.FunctionNameAbsolute,
|
|
Args: []qbtypes.FunctionArg{},
|
|
},
|
|
},
|
|
step: 60000,
|
|
checkArgs: false,
|
|
},
|
|
{
|
|
name: "no copy when fillZero already has args",
|
|
functions: []qbtypes.Function{
|
|
{
|
|
Name: qbtypes.FunctionNameFillZero,
|
|
Args: []qbtypes.FunctionArg{
|
|
{Value: 1000.0},
|
|
{Value: 2000.0},
|
|
{Value: 500.0},
|
|
},
|
|
},
|
|
{
|
|
Name: qbtypes.FunctionNameAbsolute,
|
|
},
|
|
},
|
|
step: 60000,
|
|
checkArgs: false,
|
|
},
|
|
}
|
|
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := q.prepareFillZeroArgsWithStep(tt.functions, req, tt.step)
|
|
|
|
if len(result) != len(tt.functions) {
|
|
t.Fatalf("Expected %d functions, got %d", len(tt.functions), len(result))
|
|
}
|
|
|
|
// Check if no copy was made when not needed
|
|
if tt.name == "no copy when fillZero already has args" || tt.name == "other function should not be modified" {
|
|
// Verify that the result is the same slice (no copy)
|
|
if &result[0] != &tt.functions[0] {
|
|
t.Errorf("Expected no copy, but a copy was made")
|
|
}
|
|
}
|
|
|
|
for _, fn := range result {
|
|
if fn.Name == qbtypes.FunctionNameFillZero && tt.checkArgs {
|
|
if len(fn.Args) != 3 {
|
|
t.Errorf("Expected 3 args for fillZero, got %d", len(fn.Args))
|
|
}
|
|
// Check start
|
|
if start, ok := fn.Args[0].Value.(float64); !ok || start != float64(req.Start) {
|
|
t.Errorf("Expected start %f, got %v", float64(req.Start), fn.Args[0].Value)
|
|
}
|
|
// Check end
|
|
if end, ok := fn.Args[1].Value.(float64); !ok || end != float64(req.End) {
|
|
t.Errorf("Expected end %f, got %v", float64(req.End), fn.Args[1].Value)
|
|
}
|
|
// Check step
|
|
if step, ok := fn.Args[2].Value.(float64); !ok || step != float64(tt.step) {
|
|
t.Errorf("Expected step %f, got %v", float64(tt.step), fn.Args[2].Value)
|
|
}
|
|
}
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCalculateFormulaStep(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
expression string
|
|
req *qbtypes.QueryRangeRequest
|
|
expected int64
|
|
}{
|
|
{
|
|
name: "single query reference",
|
|
expression: "A * 2",
|
|
req: &qbtypes.QueryRangeRequest{
|
|
CompositeQuery: qbtypes.CompositeQuery{
|
|
Queries: []qbtypes.QueryEnvelope{
|
|
{
|
|
Type: qbtypes.QueryTypeBuilder,
|
|
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
|
|
Name: "A",
|
|
StepInterval: qbtypes.Step{Duration: 60 * time.Second},
|
|
},
|
|
},
|
|
{
|
|
Type: qbtypes.QueryTypeBuilder,
|
|
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
|
|
Name: "B",
|
|
StepInterval: qbtypes.Step{Duration: 120 * time.Second},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: 60000, // Only A is referenced
|
|
},
|
|
{
|
|
name: "multiple query references",
|
|
expression: "A + B",
|
|
req: &qbtypes.QueryRangeRequest{
|
|
CompositeQuery: qbtypes.CompositeQuery{
|
|
Queries: []qbtypes.QueryEnvelope{
|
|
{
|
|
Type: qbtypes.QueryTypeBuilder,
|
|
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
|
|
Name: "A",
|
|
StepInterval: qbtypes.Step{Duration: 30 * time.Second},
|
|
},
|
|
},
|
|
{
|
|
Type: qbtypes.QueryTypeBuilder,
|
|
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
|
|
Name: "B",
|
|
StepInterval: qbtypes.Step{Duration: 60 * time.Second},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: 30000, // GCD of 30s and 60s
|
|
},
|
|
{
|
|
name: "complex expression",
|
|
expression: "(A + B) / C",
|
|
req: &qbtypes.QueryRangeRequest{
|
|
CompositeQuery: qbtypes.CompositeQuery{
|
|
Queries: []qbtypes.QueryEnvelope{
|
|
{
|
|
Type: qbtypes.QueryTypeBuilder,
|
|
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
|
|
Name: "A",
|
|
StepInterval: qbtypes.Step{Duration: 60 * time.Second},
|
|
},
|
|
},
|
|
{
|
|
Type: qbtypes.QueryTypeBuilder,
|
|
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
|
|
Name: "B",
|
|
StepInterval: qbtypes.Step{Duration: 120 * time.Second},
|
|
},
|
|
},
|
|
{
|
|
Type: qbtypes.QueryTypeBuilder,
|
|
Spec: qbtypes.QueryBuilderQuery[qbtypes.MetricAggregation]{
|
|
Name: "C",
|
|
StepInterval: qbtypes.Step{Duration: 180 * time.Second},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
expected: 60000, // GCD of 60s, 120s, and 180s
|
|
},
|
|
{
|
|
name: "no query references",
|
|
expression: "100",
|
|
req: &qbtypes.QueryRangeRequest{
|
|
CompositeQuery: qbtypes.CompositeQuery{
|
|
Queries: []qbtypes.QueryEnvelope{},
|
|
},
|
|
},
|
|
expected: 60000, // Default
|
|
},
|
|
}
|
|
|
|
q := &querier{}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
result := q.calculateFormulaStep(tt.expression, tt.req)
|
|
if result != tt.expected {
|
|
t.Errorf("Expected step %d, got %d", tt.expected, result)
|
|
}
|
|
})
|
|
}
|
|
}
|