ronantakizawa/codereview-bench huggingface dataset:
Repository: kubernetes/kubernetes
File: pkg/scheduler/backend/queue/unschedulable_pods_test.go (Go)

Code before:

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package queue

import (
	"sync/atomic"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/kubernetes/pkg/scheduler/framework"
	st "k8s.io/kubernetes/pkg/scheduler/testing"
	"k8s.io/kubernetes/pkg/scheduler/util"
)

type MockMetricRecorder struct {
	val atomic.Int64
}

func (m *MockMetricRecorder) Inc() {
	m.val.Add(1)
}

func (m *MockMetricRecorder) Dec() {
	m.val.Add(-1)
}

func (m *MockMetricRecorder) Clear() {
	m.val.Store(0)
}

func (m *MockMetricRecorder) Value() int64 {
	return m.val.Load()
}

func TestUnschedulablePods(t *testing.T) {
	var pods = []*v1.Pod{
		st.MakePod().Name("p0").Namespace("ns1").Annotation("annot1", "val1").NominatedNodeName("node1").Obj(),
		st.MakePod().Name("p1").Namespace("ns1").Annotation("annot", "val").Obj(),
		st.MakePod().Name("p2").Namespace("ns2").Annotation("annot2", "val2").Annotation("annot3", "val3").NominatedNodeName("node3").Obj(),
		st.MakePod().Name("p3").Namespace("ns4").Annotation("annot2", "val2").Annotation("annot3", "val3").NominatedNodeName("node1").Obj(),

Review comment (suggestion):
Can be unexported
```suggestion
type mockMetricRecorder struct {
```

Code after:

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package queue

import (
	"sync/atomic"
	"testing"

	"github.com/google/go-cmp/cmp"
	"github.com/google/go-cmp/cmp/cmpopts"
	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/util/sets"
	"k8s.io/kubernetes/pkg/scheduler/framework"
	"k8s.io/kubernetes/pkg/scheduler/metrics"
	st "k8s.io/kubernetes/pkg/scheduler/testing"
	"k8s.io/kubernetes/pkg/scheduler/util"
)

var _ metrics.MetricRecorder = &mockMetricRecorder{}

type mockMetricRecorder struct {
	val atomic.Int64
}

func (m *mockMetricRecorder) Inc() {
	m.val.Add(1)
}

func (m *mockMetricRecorder) Dec() {
	m.val.Add(-1)
}

func (m *mockMetricRecorder) Clear() {
	m.val.Store(0)
}

func (m *mockMetricRecorder) value() int64 {
	return m.val.Load()
}

func TestUnschedulablePods(t *testing.T) {
	type action string
Repository: kubernetes/kubernetes
File: pkg/scheduler/backend/queue/unschedulable_pods_test.go (Go)

Code before:
				},
			},
		},
		{
			name: "add non-gated pod, update it to gated",
			steps: []step{
				{
					action: add,
					pods:   []*framework.QueuedPodInfo{makePodInfo(pods[0], false)},
					expectedPods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], false),
					},
				},
				{
					action: update,
					pods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], true),
					},
					expectedPods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], true),
					},
				},
			},
		},
		{
			name: "add 4 ungated and 2 gate, update 2 to gated and 1 to ungated",
			steps: []step{
				{
					action: add,
					pods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], false),
						makePodInfo(pods[1], false),
						makePodInfo(pods[2], false),
						makePodInfo(pods[3], false),
						makePodInfo(pods[4], true),
						makePodInfo(pods[5], true),
					},
					expectedPods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], false),
						makePodInfo(pods[1], false),
						makePodInfo(pods[2], false),
						makePodInfo(pods[3], false),
						makePodInfo(pods[4], true),
						makePodInfo(pods[5], true),
					},
				},
				{
					action: update,
					pods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], true),
						makePodInfo(pods[1], true),

Review comment (suggestion):
```suggestion
			name: "add 4 ungated and 2 gated, update 2 to gated and 1 to ungated",
```

Code after:
			},
		},
		{
			name: "add gated pod, update it to non-gated",
			steps: []step{
				{
					action: add,
					pods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], true),
					},
					expectedPods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], true),
					},
				},
				{
					action: update,
					pods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], false),
					},
					expectedPods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], false),
					},
				},
				{
					action: delete,
					pods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], false),
					},
					expectedPods: []*framework.QueuedPodInfo{},
				},
			},
		},
		{
			name: "add non-gated pod, update it to gated",
			steps: []step{
				{
					action: add,
					pods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], false),
					},
					expectedPods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], false),
					},
				},
				{
					action: update,
					pods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], true),
					},
					expectedPods: []*framework.QueuedPodInfo{
						makePodInfo(pods[0], true),
Repository: kubernetes/kubernetes
File: pkg/kubelet/volumemanager/volume_manager.go (Go)

Code before:
		slices.Sort(mountedVolumes)
		return fmt.Errorf(
			"mounted volumes=%v: %w",
			mountedVolumes,
			err)
	}

	logger.V(3).Info("All volumes are unmounted for pod", "pod", klog.KObj(pod))
	return nil
}

func (vm *volumeManager) WaitForAllPodsUnmount(ctx context.Context, pods []*v1.Pod) error {
	if len(pods) == 0 {
		return nil
	}

	errChan := make(chan error, len(pods))

	for _, pod := range pods {
		go func(p *v1.Pod) {
			if err := vm.WaitForUnmount(ctx, p); err != nil {
				errChan <- err
			} else {
				//Send nil to signal completion even when there's no error
				errChan <- nil
			}
		}(pod)
	}

	var errors []error
	for i := 0; i < len(pods); i++ {
		if err := <-errChan; err != nil {
			errors = append(errors, err)
		}
	}

	return utilerrors.NewAggregate(errors)
}

func (vm *volumeManager) getVolumesNotInDSW(uniquePodName types.UniquePodName, expectedVolumes []string) []string {
	volumesNotInDSW := sets.New(expectedVolumes...)

	for _, volumeToMount := range vm.desiredStateOfWorld.GetVolumesToMount() {
		if volumeToMount.PodName == uniquePodName {
			volumesNotInDSW.Delete(volumeToMount.OuterVolumeSpecNames...)
		}
	}

	return sets.List(volumesNotInDSW)
}


Review comment (suggestion):
That's much better!
nit: `errChan <- vm.WaitForUnmount(ctx, p)` should be enough here.

Code after:
		slices.Sort(mountedVolumes)
		return fmt.Errorf(
			"mounted volumes=%v: %w",
			mountedVolumes,
			err)
	}

	logger.V(3).Info("All volumes are unmounted for pod", "pod", klog.KObj(pod))
	return nil
}

func (vm *volumeManager) WaitForAllPodsUnmount(ctx context.Context, pods []*v1.Pod) error {
	if len(pods) == 0 {
		return nil
	}

	funcs := make([]func() error, 0, len(pods))
	for _, pod := range pods {
		funcs = append(funcs, func() error {
			return vm.WaitForUnmount(ctx, pod)
		})
	}

	return utilerrors.AggregateGoroutines(funcs...)
}

func (vm *volumeManager) getVolumesNotInDSW(uniquePodName types.UniquePodName, expectedVolumes []string) []string {
	volumesNotInDSW := sets.New(expectedVolumes...)

	for _, volumeToMount := range vm.desiredStateOfWorld.GetVolumesToMount() {
		if volumeToMount.PodName == uniquePodName {
			volumesNotInDSW.Delete(volumeToMount.OuterVolumeSpecNames...)
		}
	}

	return sets.List(volumesNotInDSW)
}

// getUnattachedVolumes returns a list of the volumes that are expected to be attached but
// are not currently attached to the node
func (vm *volumeManager) getUnattachedVolumes(uniquePodName types.UniquePodName) []cache.VolumeToMount {
	unattachedVolumes := []cache.VolumeToMount{}
	for _, volumeToMount := range vm.desiredStateOfWorld.GetVolumesToMount() {
		if volumeToMount.PodName == uniquePodName &&
			volumeToMount.PluginIsAttachable &&
			!vm.actualStateOfWorld.VolumeExists(volumeToMount.VolumeName) {
			unattachedVolumes = append(unattachedVolumes, volumeToMount)
		}
	}
	return unattachedVolumes
}
Repository: kubernetes/kubernetes
File: pkg/kubelet/volumemanager/volume_manager.go (Go)

Code before:
			return nil
		}

		slices.Sort(mountedVolumes)
		return fmt.Errorf(
			"mounted volumes=%v: %w",
			mountedVolumes,
			err)
	}

	logger.V(3).Info("All volumes are unmounted for pod", "pod", klog.KObj(pod))
	return nil
}

func (vm *volumeManager) WaitForAllPodsUnmount(ctx context.Context, pods []*v1.Pod) error {
	if len(pods) == 0 {
		return nil
	}

	errChan := make(chan error, len(pods))

	for _, pod := range pods {
		go func(p *v1.Pod) {
			errChan <- vm.WaitForUnmount(ctx, p)
		}(pod)
	}

	var errors []error
	for i := 0; i < len(pods); i++ {
		errors = append(errors, <-errChan)
	}

	return utilerrors.NewAggregate(errors)
}

func (vm *volumeManager) getVolumesNotInDSW(uniquePodName types.UniquePodName, expectedVolumes []string) []string {
	volumesNotInDSW := sets.New(expectedVolumes...)

	for _, volumeToMount := range vm.desiredStateOfWorld.GetVolumesToMount() {
		if volumeToMount.PodName == uniquePodName {
			volumesNotInDSW.Delete(volumeToMount.OuterVolumeSpecNames...)
		}
	}

	return sets.List(volumesNotInDSW)
}

// getUnattachedVolumes returns a list of the volumes that are expected to be attached but
// are not currently attached to the node
func (vm *volumeManager) getUnattachedVolumes(uniquePodName types.UniquePodName) []cache.VolumeToMount {
	unattachedVolumes := []cache.VolumeToMount{}

Review comment (refactor):
A helper func can be used.

https://github.com/kubernetes/kubernetes/blob/31fb6f64efd7fd4b845584654972e1a55f9aab82/staging/src/k8s.io/apimachinery/pkg/util/errors/errors.go#L233-L248


Code after:
			return nil
		}

		slices.Sort(mountedVolumes)
		return fmt.Errorf(
			"mounted volumes=%v: %w",
			mountedVolumes,
			err)
	}

	logger.V(3).Info("All volumes are unmounted for pod", "pod", klog.KObj(pod))
	return nil
}

func (vm *volumeManager) WaitForAllPodsUnmount(ctx context.Context, pods []*v1.Pod) error {
	if len(pods) == 0 {
		return nil
	}

	funcs := make([]func() error, 0, len(pods))
	for _, pod := range pods {
		funcs = append(funcs, func() error {
			return vm.WaitForUnmount(ctx, pod)
		})
	}

	return utilerrors.AggregateGoroutines(funcs...)
}

func (vm *volumeManager) getVolumesNotInDSW(uniquePodName types.UniquePodName, expectedVolumes []string) []string {
	volumesNotInDSW := sets.New(expectedVolumes...)

	for _, volumeToMount := range vm.desiredStateOfWorld.GetVolumesToMount() {
		if volumeToMount.PodName == uniquePodName {
			volumesNotInDSW.Delete(volumeToMount.OuterVolumeSpecNames...)
		}
	}

	return sets.List(volumesNotInDSW)
}

// getUnattachedVolumes returns a list of the volumes that are expected to be attached but
// are not currently attached to the node
func (vm *volumeManager) getUnattachedVolumes(uniquePodName types.UniquePodName) []cache.VolumeToMount {
	unattachedVolumes := []cache.VolumeToMount{}
	for _, volumeToMount := range vm.desiredStateOfWorld.GetVolumesToMount() {
		if volumeToMount.PodName == uniquePodName &&
			volumeToMount.PluginIsAttachable &&
			!vm.actualStateOfWorld.VolumeExists(volumeToMount.VolumeName) {
			unattachedVolumes = append(unattachedVolumes, volumeToMount)
		}
Repository: kubernetes/kubernetes
File: pkg/kubelet/volumemanager/volume_manager_test.go (Go)

Code before:
}

func delayClaimBecomesBound(
	t *testing.T,
	kubeClient clientset.Interface,
	namespace, claimName string,
) {
	tCtx := ktesting.Init(t)
	time.Sleep(500 * time.Millisecond)
	volumeClaim, err :=
		kubeClient.CoreV1().PersistentVolumeClaims(namespace).Get(tCtx, claimName, metav1.GetOptions{})
	if err != nil {
		t.Errorf("Failed to get PVC: %v", err)
	}
	volumeClaim.Status = v1.PersistentVolumeClaimStatus{
		Phase: v1.ClaimBound,
	}
	_, err = kubeClient.CoreV1().PersistentVolumeClaims(namespace).Update(tCtx, volumeClaim, metav1.UpdateOptions{})
	if err != nil {
		t.Errorf("Failed to update PVC: %v", err)
	}
}

func TestWaitForAllPodsUnmount(t *testing.T) {
	tmpDir := t.TempDir()
	defer func() {
		if err := os.RemoveAll(tmpDir); err != nil {
			t.Errorf("Failed to remove temp directory: %v", err)
		}
	}()

	tests := []struct {
		name          string
		numPods       int
		podMode       v1.PersistentVolumeMode
		expectedError bool
	}{
		{
			name:          "successful unmount - single pod",
			numPods:       1,
			podMode:       "",
			expectedError: false,
		},
		{
			name:          "timeout waiting for unmount - single pod",
			numPods:       1,
			podMode:       v1.PersistentVolumeFilesystem,
			expectedError: true,
		},
		{
			name:          "concurrent unmount - multiple pods (10) with timeout errors",

Review comment (suggestion):
We don't need to remove tmpDir manually after `t.TempDir()` is used

Code after:
	}
}

func delayClaimBecomesBound(
	t *testing.T,
	kubeClient clientset.Interface,
	namespace, claimName string,
) {
	tCtx := ktesting.Init(t)
	time.Sleep(500 * time.Millisecond)
	volumeClaim, err :=
		kubeClient.CoreV1().PersistentVolumeClaims(namespace).Get(tCtx, claimName, metav1.GetOptions{})
	if err != nil {
		t.Errorf("Failed to get PVC: %v", err)
	}
	volumeClaim.Status = v1.PersistentVolumeClaimStatus{
		Phase: v1.ClaimBound,
	}
	_, err = kubeClient.CoreV1().PersistentVolumeClaims(namespace).Update(tCtx, volumeClaim, metav1.UpdateOptions{})
	if err != nil {
		t.Errorf("Failed to update PVC: %v", err)
	}
}

func TestWaitForAllPodsUnmount(t *testing.T) {
	tmpDir := t.TempDir()

	tests := []struct {
		name          string
		numPods       int
		podMode       v1.PersistentVolumeMode
		expectedError bool
	}{
		{
			name:          "successful unmount - single pod",
			numPods:       1,
			podMode:       "",
			expectedError: false,
		},
		{
			name:          "timeout waiting for unmount - single pod",
			numPods:       1,
			podMode:       v1.PersistentVolumeFilesystem,
			expectedError: true,
		},
		{
			name:          "concurrent unmount - multiple pods (10) with timeout errors",
			numPods:       10,
			podMode:       v1.PersistentVolumeFilesystem,
			expectedError: true,
		},
Repository: kubernetes/kubernetes
File: staging/src/k8s.io/api/authentication/v1/types.go (Go)

Code before:
	// +optional
	UID types.UID `json:"uid,omitempty" protobuf:"bytes,4,opt,name=uID,casttype=k8s.io/apimachinery/pkg/types.UID"`
}

// +genclient
// +genclient:nonNamespaced
// +genclient:onlyVerbs=create
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.28

// SelfSubjectReview contains the user information that the kube-apiserver has about the user making this request.
// When using impersonation, users will receive the user info of the user being impersonated.  If impersonation or
// request header authentication is used, any extra keys will have their case ignored and returned as lowercase.
type SelfSubjectReview struct {
	metav1.TypeMeta `json:",inline"`
	// metadata is standard object's metadata.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
	// status is filled in by the server with the user attributes.
	Status SelfSubjectReviewStatus `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"`
}

// SelfSubjectReviewStatus is filled by the kube-apiserver and sent back to a user.
type SelfSubjectReviewStatus struct {
	// userInfo is user attributes of the user making this request.
	// +optional
	UserInfo UserInfo `json:"userInfo,omitempty" protobuf:"bytes,1,opt,name=userInfo"`
}


Review comment (suggestion):
Maybe?
```suggestion
	// userInfo is a set of attributes belonging to the user making this request.
```

Code after:
	// +optional
	UID types.UID `json:"uid,omitempty" protobuf:"bytes,4,opt,name=uID,casttype=k8s.io/apimachinery/pkg/types.UID"`
}

// +genclient
// +genclient:nonNamespaced
// +genclient:onlyVerbs=create
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.28

// SelfSubjectReview contains the user information that the kube-apiserver has about the user making this request.
// When using impersonation, users will receive the user info of the user being impersonated.  If impersonation or
// request header authentication is used, any extra keys will have their case ignored and returned as lowercase.
type SelfSubjectReview struct {
	metav1.TypeMeta `json:",inline"`
	// metadata is standard object's metadata.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
	// status is filled in by the server with the user attributes.
	Status SelfSubjectReviewStatus `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"`
}

// SelfSubjectReviewStatus is filled by the kube-apiserver and sent back to a user.
type SelfSubjectReviewStatus struct {
	// userInfo is a set of attributes belonging to the user making this request.
	// +optional
	UserInfo UserInfo `json:"userInfo,omitempty" protobuf:"bytes,1,opt,name=userInfo"`
}
Repository: kubernetes/kubernetes
File: staging/src/k8s.io/api/authentication/v1alpha1/types.go (Go)

Code before:
	v1 "k8s.io/api/authentication/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +genclient:nonNamespaced
// +genclient:onlyVerbs=create
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.26

// SelfSubjectReview contains the user information that the kube-apiserver has about the user making this request.
// When using impersonation, users will receive the user info of the user being impersonated.  If impersonation or
// request header authentication is used, any extra keys will have their case ignored and returned as lowercase.
type SelfSubjectReview struct {
	metav1.TypeMeta `json:",inline"`
	// metadata is standard object's metadata.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
	// status is filled in by the server with the user attributes.
	Status SelfSubjectReviewStatus `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"`
}

// SelfSubjectReviewStatus is filled by the kube-apiserver and sent back to a user.
type SelfSubjectReviewStatus struct {
	// userInfo is user attributes of the user making this request.
	// +optional
	UserInfo v1.UserInfo `json:"userInfo,omitempty" protobuf:"bytes,1,opt,name=userInfo"`
}


Review comment (suggestion):
```suggestion
	// userInfo is a set of attributes belonging to the user making this request.
```

Code after:
	v1 "k8s.io/api/authentication/v1"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

// +genclient
// +genclient:nonNamespaced
// +genclient:onlyVerbs=create
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.26

// SelfSubjectReview contains the user information that the kube-apiserver has about the user making this request.
// When using impersonation, users will receive the user info of the user being impersonated.  If impersonation or
// request header authentication is used, any extra keys will have their case ignored and returned as lowercase.
type SelfSubjectReview struct {
	metav1.TypeMeta `json:",inline"`
	// metadata is the standard object's metadata.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
	// status is filled in by the server with the user attributes.
	Status SelfSubjectReviewStatus `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"`
}

// SelfSubjectReviewStatus is filled by the kube-apiserver and sent back to a user.
type SelfSubjectReviewStatus struct {
	// userInfo is a set of attributes belonging to the user making this request.
	// +optional
	UserInfo v1.UserInfo `json:"userInfo,omitempty" protobuf:"bytes,1,opt,name=userInfo"`
}
Repository: kubernetes/kubernetes
File: staging/src/k8s.io/api/authentication/v1beta1/types.go (Go)

Code before:
func (t ExtraValue) String() string {
	return fmt.Sprintf("%v", []string(t))
}

// +genclient
// +genclient:nonNamespaced
// +genclient:onlyVerbs=create
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.27

// SelfSubjectReview contains the user information that the kube-apiserver has about the user making this request.
// When using impersonation, users will receive the user info of the user being impersonated.  If impersonation or
// request header authentication is used, any extra keys will have their case ignored and returned as lowercase.
type SelfSubjectReview struct {
	metav1.TypeMeta `json:",inline"`
	// metadata is standard object's metadata.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
	// status is filled in by the server with the user attributes.
	Status SelfSubjectReviewStatus `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"`
}

// SelfSubjectReviewStatus is filled by the kube-apiserver and sent back to a user.
type SelfSubjectReviewStatus struct {
	// userInfo is user attributes of the user making this request.
	// +optional
	UserInfo v1.UserInfo `json:"userInfo,omitempty" protobuf:"bytes,1,opt,name=userInfo"`
}


Review comment (suggestion):
```suggestion
	// userInfo is a set of attributes belonging to the user making this request.
```

Code after:
func (t ExtraValue) String() string {
	return fmt.Sprintf("%v", []string(t))
}

// +genclient
// +genclient:nonNamespaced
// +genclient:onlyVerbs=create
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +k8s:prerelease-lifecycle-gen:introduced=1.27

// SelfSubjectReview contains the user information that the kube-apiserver has about the user making this request.
// When using impersonation, users will receive the user info of the user being impersonated.  If impersonation or
// request header authentication is used, any extra keys will have their case ignored and returned as lowercase.
type SelfSubjectReview struct {
	metav1.TypeMeta `json:",inline"`
	// metadata is the standard object's metadata.
	// More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#metadata
	// +optional
	metav1.ObjectMeta `json:"metadata,omitempty" protobuf:"bytes,1,opt,name=metadata"`
	// status is filled in by the server with the user attributes.
	Status SelfSubjectReviewStatus `json:"status,omitempty" protobuf:"bytes,2,opt,name=status"`
}

// SelfSubjectReviewStatus is filled by the kube-apiserver and sent back to a user.
type SelfSubjectReviewStatus struct {
	// userInfo is a set of attributes belonging to the user making this request.
	// +optional
	UserInfo v1.UserInfo `json:"userInfo,omitempty" protobuf:"bytes,1,opt,name=userInfo"`
}