Skip to content

Commit ebe5531

Browse files
committed
test(recipe): assert full strict-gap context payload including warnings
Signed-off-by: Brian Lockwood <lockwobr@gmail.com>
1 parent 3c2c076 commit ebe5531

1 file changed

Lines changed: 61 additions & 9 deletions

File tree

pkg/recipe/coverage_subsumption_test.go

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"context"
1919
stderrors "errors"
2020
"fmt"
21+
"reflect"
2122
"sort"
2223
"strings"
2324
"testing"
@@ -182,8 +183,8 @@ func TestStrictGapErrorRendering(t *testing.T) {
182183
name string
183184
gaps []strictGap
184185
excluded []ExcludedOverlay
186+
warnings []ConstraintWarning
185187
wantContains []string
186-
wantExcluded bool
187188
}{
188189
{
189190
name: "single value",
@@ -208,17 +209,26 @@ func TestStrictGapErrorRendering(t *testing.T) {
208209
// a failing constraint. The demand still stands, but the caller
209210
// needs the exclusion context or they will state the os and only
210211
// then meet the real failure.
211-
name: "constraint exclusions are attached",
212-
gaps: []strictGap{{dimension: string(FieldOS), validValues: []string{"ubuntu"}}},
213-
excluded: []ExcludedOverlay{{Name: "h100-eks-ubuntu-training"}},
212+
name: "constraint context is attached",
213+
gaps: []strictGap{{dimension: string(FieldOS), validValues: []string{"ubuntu"}}},
214+
excluded: []ExcludedOverlay{{
215+
Name: "h100-eks-ubuntu-training",
216+
Reason: ExcludedOverlayReasonConstraintFailed,
217+
}},
218+
warnings: []ConstraintWarning{{
219+
Overlay: "h100-eks-ubuntu-training",
220+
Constraint: "K8s.server.version",
221+
Expected: ">= 1.34",
222+
Actual: "1.30",
223+
Reason: "constraint not satisfied",
224+
}},
214225
wantContains: []string{"specify os (valid: ubuntu)"},
215-
wantExcluded: true,
216226
},
217227
}
218228

219229
for _, tt := range tests {
220230
t.Run(tt.name, func(t *testing.T) {
221-
err := strictGapError(criteria, tt.gaps, tt.excluded, nil)
231+
err := strictGapError(criteria, tt.gaps, tt.excluded, tt.warnings)
222232
for _, want := range tt.wantContains {
223233
if !strings.Contains(err.Error(), want) {
224234
t.Errorf("message = %q, want it to contain %q", err.Error(), want)
@@ -232,9 +242,51 @@ func TestStrictGapErrorRendering(t *testing.T) {
232242
if se.Context["uncovered"] != nil {
233243
t.Error("strict-gap failure must not populate `uncovered`; relaxation would clear it")
234244
}
235-
if (se.Context["excludedOverlays"] != nil) != tt.wantExcluded {
236-
t.Errorf("excludedOverlays present = %v, want %v",
237-
se.Context["excludedOverlays"] != nil, tt.wantExcluded)
245+
246+
// Assert the whole strictDimensions payload, not just the keys: a
247+
// caller reconstructing a retry query reads validValues, so a
248+
// regression that dropped or reordered them would otherwise pass.
249+
entries, ok := se.Context["strictDimensions"].([]map[string]any)
250+
if !ok {
251+
t.Fatalf("strictDimensions = %#v, want []map[string]any", se.Context["strictDimensions"])
252+
}
253+
if len(entries) != len(tt.gaps) {
254+
t.Fatalf("strictDimensions has %d entries, want %d", len(entries), len(tt.gaps))
255+
}
256+
for i, gap := range tt.gaps {
257+
if entries[i]["dimension"] != gap.dimension {
258+
t.Errorf("entry %d dimension = %v, want %v", i, entries[i]["dimension"], gap.dimension)
259+
}
260+
values, ok := entries[i]["validValues"].([]string)
261+
if !ok {
262+
t.Errorf("entry %d validValues = %#v, want []string", i, entries[i]["validValues"])
263+
continue
264+
}
265+
if !equalStrings(values, gap.validValues) {
266+
t.Errorf("entry %d validValues = %v, want %v", i, values, gap.validValues)
267+
}
268+
}
269+
270+
// excludedOverlays / constraintWarnings are attached verbatim, and
271+
// absent rather than empty when there is nothing to report.
272+
if tt.excluded == nil {
273+
if se.Context["excludedOverlays"] != nil {
274+
t.Errorf("excludedOverlays = %#v, want absent", se.Context["excludedOverlays"])
275+
}
276+
} else if got, ok := se.Context["excludedOverlays"].([]ExcludedOverlay); !ok {
277+
t.Errorf("excludedOverlays = %#v, want []ExcludedOverlay", se.Context["excludedOverlays"])
278+
} else if !reflect.DeepEqual(got, tt.excluded) {
279+
t.Errorf("excludedOverlays = %+v, want %+v", got, tt.excluded)
280+
}
281+
282+
if tt.warnings == nil {
283+
if se.Context["constraintWarnings"] != nil {
284+
t.Errorf("constraintWarnings = %#v, want absent", se.Context["constraintWarnings"])
285+
}
286+
} else if got, ok := se.Context["constraintWarnings"].([]ConstraintWarning); !ok {
287+
t.Errorf("constraintWarnings = %#v, want []ConstraintWarning", se.Context["constraintWarnings"])
288+
} else if !reflect.DeepEqual(got, tt.warnings) {
289+
t.Errorf("constraintWarnings = %+v, want %+v", got, tt.warnings)
238290
}
239291

240292
// The golden matrix classifies via this extraction, so exercise it

0 commit comments

Comments
 (0)