blob: 5519ab0d5349cbdfebc42229f984acb67a4e8a2d [file] [log] [blame]
package preflightqueryprocessor
import (
"net/url"
"testing"
"github.com/stretchr/testify/assert"
"go.skia.org/infra/go/paramtools"
"go.skia.org/infra/go/query"
)
func TestProcessTraceIds_MissingKeysAreAddedAsEmptyStrings(t *testing.T) {
q, err := query.New(url.Values{"benchmark": []string{"b1"}})
assert.NoError(t, err)
processor := NewPreflightMainQueryProcessor(q)
processor.SetKeysToDetectMissing([]string{"bot", "test"})
inputParams := []paramtools.Params{
// Trace 1: Has 'bot', missing 'test'
{"benchmark": "b1", "bot": "bot1"},
// Trace 2: Has 'test', missing 'bot'
{"benchmark": "b1", "test": "test1"},
// Trace 3: Has both
{"benchmark": "b1", "bot": "bot2", "test": "test2"},
// Trace 4: Missing both
{"benchmark": "b1"},
}
inputChannel := make(chan paramtools.Params, len(inputParams))
for _, p := range inputParams {
inputChannel <- p
}
close(inputChannel)
processedParams := processor.ProcessTraceIds(inputChannel)
assert.Len(t, processedParams, 4)
// Verify Trace 1
assert.Equal(t, "bot1", processedParams[0]["bot"])
_, ok := processedParams[0]["test"]
assert.False(t, ok, "key 'test' should be missing in Trace 1 params")
// Verify Trace 2
_, ok = processedParams[1]["bot"]
assert.False(t, ok, "key 'bot' should be missing in Trace 2 params")
assert.Equal(t, "test1", processedParams[1]["test"])
// Verify Trace 3
assert.Equal(t, "bot2", processedParams[2]["bot"])
assert.Equal(t, "test2", processedParams[2]["test"])
// Verify Trace 4
_, ok = processedParams[3]["bot"]
assert.False(t, ok, "key 'bot' should be missing in Trace 4 params")
_, ok = processedParams[3]["test"]
assert.False(t, ok, "key 'test' should be missing in Trace 4 params")
// Verify ParamSet aggregation
paramSet := processor.GetParamSet()
assert.Contains(t, (*paramSet)["bot"], "")
assert.Contains(t, (*paramSet)["test"], "")
// Verify count
assert.Equal(t, 4, processor.GetCount())
}
func TestMainQuery_SentinelMixed(t *testing.T) {
// Query: a=[v1, __missing__]
values := url.Values{
"a": []string{"v1", MissingValueSentinel},
"b": []string{"v2"},
}
q, err := query.New(values)
assert.NoError(t, err)
// Verify initial query has sentinel
assert.Contains(t, q.Params[0].Values, MissingValueSentinel)
// Create processor (this should clone and modify query)
p := NewPreflightMainQueryProcessor(q)
// Verify original query is UNTOUCHED
assert.Contains(t, q.Params[0].Values, MissingValueSentinel, "Original query should not be modified")
// Verify internal query has key REMOVED (superset fetch)
internalQ := p.GetQuery()
for _, param := range internalQ.Params {
if param.Key() == "a" {
t.Errorf("Key 'a' should have been removed from internal query")
}
}
inputChannel := make(chan paramtools.Params, 3)
// Trace 1: a=v1. Should match.
inputChannel <- paramtools.Params{"a": "v1", "b": "v2"}
// Trace 2: a=missing. Should match.
inputChannel <- paramtools.Params{"b": "v2"}
// Trace 3: a=v3. Should NOT match.
inputChannel <- paramtools.Params{"a": "v3", "b": "v2"}
close(inputChannel)
out := p.ProcessTraceIds(inputChannel)
assert.Len(t, out, 2)
assert.Equal(t, "v1", out[0]["a"])
_, ok := out[1]["a"]
assert.False(t, ok)
}
func TestMainQuery_SentinelOnly(t *testing.T) {
// Query: a=__missing__
values := url.Values{
"a": []string{MissingValueSentinel},
}
q, err := query.New(values)
assert.NoError(t, err)
p := NewPreflightMainQueryProcessor(q)
inputChannel := make(chan paramtools.Params, 2)
inputChannel <- paramtools.Params{"b": "v2"} // Missing "a". Match.
inputChannel <- paramtools.Params{"a": "v1", "b": "v2"} // Has "a". No Match.
close(inputChannel)
out := p.ProcessTraceIds(inputChannel)
assert.Len(t, out, 1)
_, ok := out[0]["a"]
assert.False(t, ok)
}
func TestSubQuery_Sentinel(t *testing.T) {
// SubQuery logic: Collect values for key "b", given filter on "a".
// Query: a=[v1, __missing__]
values := url.Values{
"a": []string{"v1", MissingValueSentinel},
}
q, err := query.New(values)
assert.NoError(t, err)
// Create a dummy main processor (required for shared state)
mainP := NewPreflightMainQueryProcessor(q)
// Create sub processor for key "b"
// SubQuery uses same query params as main query
subP := NewPreflightSubQueryProcessor(mainP, q, "b")
inputChannel := make(chan paramtools.Params, 4)
// Trace 1: a=v1, b=val1. Match.
inputChannel <- paramtools.Params{"a": "v1", "b": "val1"}
// Trace 2: a=missing, b=val2. Match.
inputChannel <- paramtools.Params{"b": "val2"}
// Trace 3: a=v2, b=val3. No Match.
inputChannel <- paramtools.Params{"a": "v2", "b": "val3"}
// Trace 4: a=v1, b missing. Match (but no value for b).
inputChannel <- paramtools.Params{"a": "v1"}
close(inputChannel)
// Process
subP.ProcessTraceIds(inputChannel)
subP.Finalize()
// Verify ParamSet in main processor (shared)
ps := mainP.GetParamSet()
assert.Contains(t, (*ps)["b"], "val1")
assert.Contains(t, (*ps)["b"], "val2")
assert.NotContains(t, (*ps)["b"], "val3")
}