Repository: kubernetes/kubernetes
File: pkg/api/testing/validation.go (Go)

Code before:
	// The imperative validation may produce duplicate errors, which is not supported by the ErrorMatcher.
	// TODO: remove this once ErrorMatcher has been extended to handle this form of deduplication.
	imperativeErrs = deDuplicateErrors(imperativeErrs, equivalenceMatcher)

	equivalenceMatcher.Test(t, imperativeErrs, declarativeTakeoverErrs)
}

// deDuplicateErrors removes duplicate errors from an ErrorList based on the provided matcher.
func deDuplicateErrors(errs field.ErrorList, matcher field.ErrorMatcher) field.ErrorList {
	var deduped field.ErrorList
	for _, err := range errs {
		found := false
		for _, existingErr := range deduped {
			if matcher.Matches(existingErr, err) {
				found = true
				break
			}
		}
		if !found {
			deduped = append(deduped, err)
		}
	}
	return deduped
}

// verifyDeclarativeValidations runs declarative validation directly without using strategy.go utilities. It uses scheme to find find declarative validations for a kind.
// This test ensures that the errors are coming from the declarative validations only.
func verifyDeclarativeValidations(t *testing.T, ctx context.Context, obj, old runtime.Object, expectedErrs field.ErrorList, opt *validationOption) {
	t.Helper()
	t.Run("declarative validation", func(t *testing.T) {
		gvks, _, err := legacyscheme.Scheme.ObjectKinds(obj)
		if err != nil {
			t.Fatalf("failed to get GVKs: %v", err)
		}
		if len(gvks) == 0 {
			t.Fatal("no GVKs found for object")
		}
		gk := gvks[0].GroupKind()

		info, ok := genericapirequest.RequestInfoFrom(ctx)
		if !ok {
			t.Fatal("no RequestInfo found in context")
		}
		targetGV := schema.GroupVersion{Group: gk.Group, Version: info.APIVersion}

		versionedObj, err := legacyscheme.Scheme.ConvertToVersion(obj, targetGV)
		if err != nil {
			t.Errorf("failed to convert to %s: %v", targetGV, err)
		}

		var errs field.ErrorList

Review comment (suggestion):
```suggestion
// verifyDeclarativeValidations runs declarative validation directly without using strategy.go utilities. It uses scheme to find declarative validations for a kind.
```

Code after:
			t.Errorf("expected no errors, but got: %v", declarativeBetaEnabledErrs)
		}

		// Ensure no mismatches were logged/metrics incremented
		testutil.AssertVectorCount(t, "apiserver_validation_declarative_validation_mismatch_total", nil, 0)
	})

	// 2. Declarative Validation with Beta Gate Disabled
	t.Run("with declarative validation (Beta disabled)", func(t *testing.T) {
		validationmetrics.ResetValidationMetricsInstance()
		featuregatetesting.SetFeatureGatesDuringTest(t, utilfeature.DefaultFeatureGate, featuregatetesting.FeatureOverrides{
			features.DeclarativeValidation:     true,
			features.DeclarativeValidationBeta: false,
		})
		declarativeBetaDisabledErrs = runValidations(ctx)

		if len(expectedErrs) > 0 {
			errOutputMatcher.Test(t, expectedErrs, declarativeBetaDisabledErrs)
		} else if len(declarativeBetaDisabledErrs) != 0 {
			t.Errorf("expected no errors, but got: %v", declarativeBetaDisabledErrs)
		}

		// Ensure no mismatches were logged/metrics incremented
		testutil.AssertVectorCount(t, "apiserver_validation_declarative_validation_mismatch_total", nil, 0)
	})
	// 3. Legacy Hand Written Validation
	// TODO: Remove this test case in 1.39 when emulation for 1.35 is no longer needed.
	t.Run("hand written validation", func(t *testing.T) {
		// Even when DeclarativeValidation gate is disabled, if the object's strategy has explicit
		// declarative enforcement enabled, Standard declarative validations still run and are enforced.
		// Emulating 1.35 ensures the DeclarativeValidationBeta gate is also effectively disabled (evaluated as false)
		// because the feature gate was not introduced until 1.36.
		featuregatetesting.SetFeatureGateEmulationVersionDuringTest(t, utilfeature.DefaultFeatureGate, version.MustParse("1.35"))
		featuregatetesting.SetFeatureGatesDuringTest(t, utilfeature.DefaultFeatureGate, featuregatetesting.FeatureOverrides{
			features.DeclarativeValidation: false,
		})
		imperativeErrs = runValidations(ctx)

		if len(expectedErrs) > 0 {
			errOutputMatcher.Test(t, expectedErrs, imperativeErrs)
		} else if len(imperativeErrs) != 0 {
			t.Errorf("expected no errors, but got: %v", imperativeErrs)
		}
	})

	// 4. Declarative Validation with All Rules Enforced (Testing Only)
	// This sub-test ensures that all declarative validation rules (including those marked as Alpha)
	// are correctly implemented and match the expected errors. It uses a special context
	// to force enforcement of all declarative rules and filter out their handwritten counterparts.
	t.Run("with declarative validation (All Rules Enforced)", func(t *testing.T) {
		validationmetrics.ResetValidationMetricsInstance()