Consolidate Distributor template parsing

This commit is contained in:
2026-08-13 03:55:03 +00:00
parent fb891fad07
commit 965f16d7a4
2 changed files with 60 additions and 51 deletions

View File

@@ -1725,43 +1725,59 @@ func TestDistributorBatchTemplateRendering(t *testing.T) {
}
}
func TestDistributorBatchTemplateRejectsUnknownAndMalformedVariables(t *testing.T) {
func TestDistributorTemplateRejectsUnknownVariables(t *testing.T) {
tests := []struct {
name string
template string
render func(string) error
}{
{name: "Unknown", template: "{report_id}"},
{name: "Unclosed", template: "{batch"},
{name: "Unopened", template: "batch}"},
{name: "Empty", template: "{}"},
{
name: "SingleReport",
template: "{unknown}",
render: func(template string) error {
_, err := RenderDistributorBundleID(template, DistributorTemplateValues{})
return err
},
},
{
name: "Batch",
template: "{report_id}",
render: func(template string) error {
_, err := RenderDistributorBatchBundleID(template, DistributorBatchTemplateValues{})
return err
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := RenderDistributorBatchBundleID(tt.template, DistributorBatchTemplateValues{})
err := tt.render(tt.template)
if err == nil {
t.Fatal("RenderDistributorBatchBundleID() error = nil, want error")
t.Fatal("rendering error = nil, want error")
}
})
}
}
func TestDistributorTemplateRejectsUnknownAndMalformedVariables(t *testing.T) {
func TestDistributorTemplateParserRejectsMalformedVariables(t *testing.T) {
const name = "notify.distributor.bundle_id_template"
tests := []struct {
name string
template string
wantErr string
}{
{name: "Unknown", template: "{unknown}"},
{name: "Unclosed", template: "{location_id"},
{name: "Unopened", template: "location_id}"},
{name: "Empty", template: "{}"},
{name: "Unclosed", template: "{location_id", wantErr: name + " contains an unclosed template variable"},
{name: "Unopened", template: "location_id}", wantErr: name + " contains an unopened template variable"},
{name: "Empty", template: "{}", wantErr: name + " contains an empty template variable"},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
_, err := RenderDistributorBundleID(tt.template, DistributorTemplateValues{})
if err == nil {
t.Fatal("RenderDistributorBundleID() error = nil, want error")
_, err := renderDistributorTemplate(name, tt.template, func(variable string) (string, bool) {
return "value", variable == "location_id"
})
if err == nil || err.Error() != tt.wantErr {
t.Fatalf("error = %v, want %q", err, tt.wantErr)
}
})
}

View File

@@ -78,7 +78,7 @@ var distributorBatchIdempotencyTemplateVariables = map[string]struct{}{
var distributorBatchPipelineTemplateVariables = distributorBatchTemplateVariables
func RenderDistributorBundleID(template string, values DistributorTemplateValues) (string, error) {
rendered, err := renderDistributorTemplate("notify.distributor.bundle_id_template", template, values, distributorTemplateVariables)
rendered, err := renderDistributorTemplate("notify.distributor.bundle_id_template", template, newDistributorTemplateResolver(values, distributorTemplateVariables))
if err != nil {
return "", err
}
@@ -89,7 +89,7 @@ func RenderDistributorBundleID(template string, values DistributorTemplateValues
}
func RenderDistributorPipelineID(template string, values DistributorTemplateValues) (string, error) {
rendered, err := renderDistributorTemplate("notify.distributor.pipeline_id_template", template, values, distributorPipelineTemplateVariables)
rendered, err := renderDistributorTemplate("notify.distributor.pipeline_id_template", template, newDistributorTemplateResolver(values, distributorPipelineTemplateVariables))
if err != nil {
return "", err
}
@@ -100,7 +100,7 @@ func RenderDistributorPipelineID(template string, values DistributorTemplateValu
}
func RenderDistributorIdempotencyKey(template string, values DistributorTemplateValues) (string, error) {
rendered, err := renderDistributorTemplate("notify.distributor.idempotency_key_template", template, values, distributorIdempotencyTemplateVariables)
rendered, err := renderDistributorTemplate("notify.distributor.idempotency_key_template", template, newDistributorTemplateResolver(values, distributorIdempotencyTemplateVariables))
if err != nil {
return "", err
}
@@ -111,7 +111,7 @@ func RenderDistributorIdempotencyKey(template string, values DistributorTemplate
}
func RenderDistributorBatchBundleID(template string, values DistributorBatchTemplateValues) (string, error) {
rendered, err := renderDistributorBatchTemplate("notify.distributor.batch.bundle_id_template", template, values, distributorBatchTemplateVariables)
rendered, err := renderDistributorTemplate("notify.distributor.batch.bundle_id_template", template, newDistributorBatchTemplateResolver(values, distributorBatchTemplateVariables))
if err != nil {
return "", err
}
@@ -122,7 +122,7 @@ func RenderDistributorBatchBundleID(template string, values DistributorBatchTemp
}
func RenderDistributorBatchPipelineID(template string, values DistributorBatchTemplateValues) (string, error) {
rendered, err := renderDistributorBatchTemplate("notify.distributor.batch.pipeline_id_template", template, values, distributorBatchPipelineTemplateVariables)
rendered, err := renderDistributorTemplate("notify.distributor.batch.pipeline_id_template", template, newDistributorBatchTemplateResolver(values, distributorBatchPipelineTemplateVariables))
if err != nil {
return "", err
}
@@ -133,7 +133,7 @@ func RenderDistributorBatchPipelineID(template string, values DistributorBatchTe
}
func RenderDistributorBatchIdempotencyKey(template string, values DistributorBatchTemplateValues) (string, error) {
rendered, err := renderDistributorBatchTemplate("notify.distributor.batch.idempotency_key_template", template, values, distributorBatchIdempotencyTemplateVariables)
rendered, err := renderDistributorTemplate("notify.distributor.batch.idempotency_key_template", template, newDistributorBatchTemplateResolver(values, distributorBatchIdempotencyTemplateVariables))
if err != nil {
return "", err
}
@@ -151,7 +151,7 @@ func RenderDistributorReportPaths(name string, templates []string, values Distri
seen := make(map[string]struct{}, len(templates))
for i, template := range templates {
itemName := fmt.Sprintf("%s[%d]", name, i)
rendered, err := renderDistributorTemplate(itemName, template, values, distributorTemplateVariables)
rendered, err := renderDistributorTemplate(itemName, template, newDistributorTemplateResolver(values, distributorTemplateVariables))
if err != nil {
return nil, err
}
@@ -168,16 +168,18 @@ func RenderDistributorReportPaths(name string, templates []string, values Distri
}
func validateDistributorTemplate(name, template string, allowed map[string]struct{}) error {
_, err := renderDistributorTemplate(name, template, DistributorTemplateValues{}, allowed)
_, err := renderDistributorTemplate(name, template, newDistributorTemplateResolver(DistributorTemplateValues{}, allowed))
return err
}
func validateDistributorBatchTemplate(name, template string, allowed map[string]struct{}) error {
_, err := renderDistributorBatchTemplate(name, template, DistributorBatchTemplateValues{}, allowed)
_, err := renderDistributorTemplate(name, template, newDistributorBatchTemplateResolver(DistributorBatchTemplateValues{}, allowed))
return err
}
func renderDistributorTemplate(name, template string, values DistributorTemplateValues, allowed map[string]struct{}) (string, error) {
type distributorTemplateResolver func(string) (string, bool)
func renderDistributorTemplate(name, template string, resolve distributorTemplateResolver) (string, error) {
var rendered strings.Builder
for i := 0; i < len(template); {
switch template[i] {
@@ -190,10 +192,11 @@ func renderDistributorTemplate(name, template string, values DistributorTemplate
if variable == "" {
return "", fmt.Errorf("%s contains an empty template variable", name)
}
if _, ok := allowed[variable]; !ok {
value, ok := resolve(variable)
if !ok {
return "", fmt.Errorf("%s contains unknown template variable %q", name, variable)
}
rendered.WriteString(distributorTemplateValue(variable, values))
rendered.WriteString(value)
i += end + 2
case '}':
return "", fmt.Errorf("%s contains an unopened template variable", name)
@@ -205,32 +208,22 @@ func renderDistributorTemplate(name, template string, values DistributorTemplate
return rendered.String(), nil
}
func renderDistributorBatchTemplate(name, template string, values DistributorBatchTemplateValues, allowed map[string]struct{}) (string, error) {
var rendered strings.Builder
for i := 0; i < len(template); {
switch template[i] {
case '{':
end := strings.IndexByte(template[i+1:], '}')
if end < 0 {
return "", fmt.Errorf("%s contains an unclosed template variable", name)
}
variable := template[i+1 : i+1+end]
if variable == "" {
return "", fmt.Errorf("%s contains an empty template variable", name)
}
if _, ok := allowed[variable]; !ok {
return "", fmt.Errorf("%s contains unknown template variable %q", name, variable)
}
rendered.WriteString(distributorBatchTemplateValue(variable, values))
i += end + 2
case '}':
return "", fmt.Errorf("%s contains an unopened template variable", name)
default:
rendered.WriteByte(template[i])
i++
func newDistributorTemplateResolver(values DistributorTemplateValues, allowed map[string]struct{}) distributorTemplateResolver {
return func(variable string) (string, bool) {
if _, ok := allowed[variable]; !ok {
return "", false
}
return distributorTemplateValue(variable, values), true
}
}
func newDistributorBatchTemplateResolver(values DistributorBatchTemplateValues, allowed map[string]struct{}) distributorTemplateResolver {
return func(variable string) (string, bool) {
if _, ok := allowed[variable]; !ok {
return "", false
}
return distributorBatchTemplateValue(variable, values), true
}
return rendered.String(), nil
}
func distributorTemplateValue(variable string, values DistributorTemplateValues) string {