/*
Copyright 2021 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    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 v1beta1

import (
	"testing"
	"time"

	"github.com/google/go-cmp/cmp"

	v1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/resource"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	logsapi "k8s.io/component-base/logs/api/v1"
	"k8s.io/kubelet/config/v1beta1"
	"k8s.io/kubernetes/pkg/cluster/ports"
	"k8s.io/kubernetes/pkg/kubelet/qos"
	kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
	"k8s.io/utils/ptr"
)

func TestSetDefaultsKubeletConfiguration(t *testing.T) {
	tests := []struct {
		name     string
		config   *v1beta1.KubeletConfiguration
		expected *v1beta1.KubeletConfiguration
	}{
		{
			"empty config",
			&v1beta1.KubeletConfiguration{},
			&v1beta1.KubeletConfiguration{
				EnableServer:       ptr.To(true),
				SyncFrequency:      metav1.Duration{Duration: 1 * time.Minute},
				FileCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				HTTPCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				Address:            "0.0.0.0",
				Port:               ports.KubeletPort,
				Authentication: v1beta1.KubeletAuthentication{
					Anonymous: v1beta1.KubeletAnonymousAuthentication{Enabled: ptr.To(false)},
					Webhook: v1beta1.KubeletWebhookAuthentication{
						Enabled:  ptr.To(true),
						CacheTTL: metav1.Duration{Duration: 2 * time.Minute},
					},
				},
				Authorization: v1beta1.KubeletAuthorization{
					Mode: v1beta1.KubeletAuthorizationModeWebhook,
					Webhook: v1beta1.KubeletWebhookAuthorization{
						CacheAuthorizedTTL:   metav1.Duration{Duration: 5 * time.Minute},
						CacheUnauthorizedTTL: metav1.Duration{Duration: 30 * time.Second},
					},
				},
				RegistryPullQPS:                           ptr.To[int32](5),
				RegistryBurst:                             10,
				EventRecordQPS:                            ptr.To[int32](50),
				EventBurst:                                100,
				EnableDebuggingHandlers:                   ptr.To(true),
				HealthzPort:                               ptr.To[int32](10248),
				HealthzBindAddress:                        "127.0.0.1",
				OOMScoreAdj:                               ptr.To(int32(qos.KubeletOOMScoreAdj)),
				StreamingConnectionIdleTimeout:            metav1.Duration{Duration: 4 * time.Hour},
				NodeStatusUpdateFrequency:                 metav1.Duration{Duration: 10 * time.Second},
				NodeStatusReportFrequency:                 metav1.Duration{Duration: 5 * time.Minute},
				NodeLeaseDurationSeconds:                  40,
				ImageMinimumGCAge:                         metav1.Duration{Duration: 2 * time.Minute},
				ImageMaximumGCAge:                         metav1.Duration{},
				ImagePullCredentialsVerificationPolicy:    "NeverVerifyPreloadedImages",
				ImageGCHighThresholdPercent:               ptr.To[int32](85),
				ImageGCLowThresholdPercent:                ptr.To[int32](80),
				ContainerRuntimeEndpoint:                  "unix:///run/containerd/containerd.sock",
				VolumeStatsAggPeriod:                      metav1.Duration{Duration: time.Minute},
				CgroupsPerQOS:                             ptr.To(true),
				CgroupDriver:                              "cgroupfs",
				CPUManagerPolicy:                          "none",
				CPUManagerReconcilePeriod:                 metav1.Duration{Duration: 10 * time.Second},
				MemoryManagerPolicy:                       v1beta1.NoneMemoryManagerPolicy,
				TopologyManagerPolicy:                     v1beta1.NoneTopologyManagerPolicy,
				TopologyManagerScope:                      v1beta1.ContainerTopologyManagerScope,
				RuntimeRequestTimeout:                     metav1.Duration{Duration: 2 * time.Minute},
				HairpinMode:                               v1beta1.PromiscuousBridge,
				MaxPods:                                   110,
				PodPidsLimit:                              ptr.To[int64](-1),
				ResolverConfig:                            ptr.To(kubetypes.ResolvConfDefault),
				CPUCFSQuota:                               ptr.To(true),
				CPUCFSQuotaPeriod:                         &metav1.Duration{Duration: 100 * time.Millisecond},
				NodeStatusMaxImages:                       ptr.To[int32](50),
				MaxOpenFiles:                              1000000,
				ContentType:                               "application/vnd.kubernetes.protobuf",
				KubeAPIQPS:                                ptr.To[int32](50),
				KubeAPIBurst:                              100,
				SerializeImagePulls:                       ptr.To(true),
				MaxParallelImagePulls:                     nil,
				EvictionHard:                              nil,
				EvictionPressureTransitionPeriod:          metav1.Duration{Duration: 5 * time.Minute},
				MergeDefaultEvictionSettings:              ptr.To(false),
				EnableControllerAttachDetach:              ptr.To(true),
				MakeIPTablesUtilChains:                    ptr.To(true),
				IPTablesMasqueradeBit:                     ptr.To[int32](DefaultIPTablesMasqueradeBit),
				IPTablesDropBit:                           ptr.To[int32](DefaultIPTablesDropBit),
				FailSwapOn:                                ptr.To(true),
				ContainerLogMaxSize:                       "10Mi",
				ContainerLogMaxFiles:                      ptr.To[int32](5),
				ContainerLogMaxWorkers:                    ptr.To[int32](1),
				ContainerLogMonitorInterval:               &metav1.Duration{Duration: 10 * time.Second},
				ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
				EnforceNodeAllocatable:                    DefaultNodeAllocatableEnforcement,
				VolumePluginDir:                           DefaultVolumePluginDir,
				Logging: logsapi.LoggingConfiguration{
					Format:         "text",
					FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
				},
				EnableSystemLogHandler:        ptr.To(true),
				EnableProfilingHandler:        ptr.To(true),
				EnableDebugFlagsHandler:       ptr.To(true),
				SeccompDefault:                ptr.To(false),
				FailCgroupV1:                  ptr.To(true),
				MemoryThrottlingFactor:        ptr.To(DefaultMemoryThrottlingFactor),
				MemoryReservationPolicy:       v1beta1.NoneMemoryReservationPolicy,
				RegisterNode:                  ptr.To(true),
				LocalStorageCapacityIsolation: ptr.To(true),
				PodLogsDir:                    DefaultPodLogsDir,
				SingleProcessOOMKill:          nil,
				CrashLoopBackOff: v1beta1.CrashLoopBackOffConfig{
					MaxContainerRestartPeriod: &metav1.Duration{Duration: MaxContainerBackOff},
				},
			},
		},
		{
			"all negative",
			&v1beta1.KubeletConfiguration{
				EnableServer:       ptr.To(false),
				StaticPodPath:      "",
				SyncFrequency:      zeroDuration,
				FileCheckFrequency: zeroDuration,
				HTTPCheckFrequency: zeroDuration,
				StaticPodURL:       "",
				StaticPodURLHeader: map[string][]string{},
				Address:            "",
				Port:               0,
				ReadOnlyPort:       0,
				TLSCertFile:        "",
				TLSPrivateKeyFile:  "",
				TLSCipherSuites:    []string{},
				TLSMinVersion:      "",
				RotateCertificates: false,
				ServerTLSBootstrap: false,
				Authentication: v1beta1.KubeletAuthentication{
					X509: v1beta1.KubeletX509Authentication{ClientCAFile: ""},
					Webhook: v1beta1.KubeletWebhookAuthentication{
						Enabled:  ptr.To(false),
						CacheTTL: zeroDuration,
					},
					Anonymous: v1beta1.KubeletAnonymousAuthentication{Enabled: ptr.To(false)},
				},
				Authorization: v1beta1.KubeletAuthorization{
					Mode: v1beta1.KubeletAuthorizationModeWebhook,
					Webhook: v1beta1.KubeletWebhookAuthorization{
						CacheAuthorizedTTL:   zeroDuration,
						CacheUnauthorizedTTL: zeroDuration,
					},
				},
				RegistryPullQPS:                        ptr.To[int32](0),
				RegistryBurst:                          0,
				EventRecordQPS:                         ptr.To[int32](0),
				EventBurst:                             0,
				EnableDebuggingHandlers:                ptr.To(false),
				EnableContentionProfiling:              false,
				HealthzPort:                            ptr.To[int32](0),
				HealthzBindAddress:                     "",
				OOMScoreAdj:                            ptr.To[int32](0),
				ClusterDomain:                          "",
				ClusterDNS:                             []string{},
				StreamingConnectionIdleTimeout:         zeroDuration,
				NodeStatusUpdateFrequency:              zeroDuration,
				NodeStatusReportFrequency:              zeroDuration,
				NodeLeaseDurationSeconds:               0,
				ContainerRuntimeEndpoint:               "unix:///run/containerd/containerd.sock",
				ImageMinimumGCAge:                      zeroDuration,
				ImagePullCredentialsVerificationPolicy: "",
				ImageGCHighThresholdPercent:            ptr.To[int32](0),
				ImageGCLowThresholdPercent:             ptr.To[int32](0),
				VolumeStatsAggPeriod:                   zeroDuration,
				KubeletCgroups:                         "",
				SystemCgroups:                          "",
				CgroupRoot:                             "",
				CgroupsPerQOS:                          ptr.To(false),
				CgroupDriver:                           "",
				CPUManagerPolicy:                       "",
				CPUManagerPolicyOptions:                map[string]string{},
				CPUManagerReconcilePeriod:              zeroDuration,
				MemoryManagerPolicy:                    "",
				TopologyManagerPolicy:                  "",
				TopologyManagerScope:                   "",
				QOSReserved:                            map[string]string{},
				RuntimeRequestTimeout:                  zeroDuration,
				HairpinMode:                            "",
				MaxPods:                                0,
				PodCIDR:                                "",
				PodPidsLimit:                           ptr.To[int64](0),
				ResolverConfig:                         ptr.To(""),
				RunOnce:                                false,
				CPUCFSQuota:                            ptr.To(false),
				CPUCFSQuotaPeriod:                      &zeroDuration,
				NodeStatusMaxImages:                    ptr.To[int32](0),
				MaxOpenFiles:                           0,
				ContentType:                            "",
				KubeAPIQPS:                             ptr.To[int32](0),
				KubeAPIBurst:                           0,
				SerializeImagePulls:                    ptr.To(false),
				MaxParallelImagePulls:                  nil,
				EvictionHard:                           map[string]string{},
				EvictionSoft:                           map[string]string{},
				EvictionSoftGracePeriod:                map[string]string{},
				EvictionPressureTransitionPeriod:       zeroDuration,
				EvictionMaxPodGracePeriod:              0,
				EvictionMinimumReclaim:                 map[string]string{},
				MergeDefaultEvictionSettings:           ptr.To(false),
				PodsPerCore:                            0,
				EnableControllerAttachDetach:           ptr.To(false),
				ProtectKernelDefaults:                  false,
				MakeIPTablesUtilChains:                 ptr.To(false),
				IPTablesMasqueradeBit:                  ptr.To[int32](0),
				IPTablesDropBit:                        ptr.To[int32](0),
				FeatureGates:                           map[string]bool{},
				FailSwapOn:                             ptr.To(false),
				MemorySwap:                             v1beta1.MemorySwapConfiguration{SwapBehavior: ""},
				ContainerLogMaxSize:                    "",
				ContainerLogMaxFiles:                   ptr.To[int32](0),
				ContainerLogMaxWorkers:                 ptr.To[int32](1),
				ContainerLogMonitorInterval:            &metav1.Duration{Duration: 10 * time.Second},
				ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
				SystemReserved:              map[string]string{},
				KubeReserved:                map[string]string{},
				ReservedSystemCPUs:          "",
				ShowHiddenMetricsForVersion: "",
				SystemReservedCgroup:        "",
				KubeReservedCgroup:          "",
				EnforceNodeAllocatable:      []string{},
				AllowedUnsafeSysctls:        []string{},
				VolumePluginDir:             "",
				ProviderID:                  "",
				KernelMemcgNotification:     false,
				Logging: logsapi.LoggingConfiguration{
					Format:         "",
					FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
				},
				EnableSystemLogHandler:          ptr.To(false),
				ShutdownGracePeriod:             zeroDuration,
				ShutdownGracePeriodCriticalPods: zeroDuration,
				ReservedMemory:                  []v1beta1.MemoryReservation{},
				EnableProfilingHandler:          ptr.To(false),
				EnableDebugFlagsHandler:         ptr.To(false),
				SeccompDefault:                  ptr.To(false),
				FailCgroupV1:                    ptr.To(true),
				MemoryThrottlingFactor:          ptr.To[float64](0),
				MemoryReservationPolicy:         v1beta1.NoneMemoryReservationPolicy,
				RegisterNode:                    ptr.To(false),
				LocalStorageCapacityIsolation:   ptr.To(false),
				PodLogsDir:                      "",
				SingleProcessOOMKill:            ptr.To(false),
			},
			&v1beta1.KubeletConfiguration{
				EnableServer:       ptr.To(false),
				SyncFrequency:      metav1.Duration{Duration: 1 * time.Minute},
				FileCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				HTTPCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				StaticPodURLHeader: map[string][]string{},
				Address:            "0.0.0.0",
				Port:               10250,
				TLSCipherSuites:    []string{},
				Authentication: v1beta1.KubeletAuthentication{
					X509: v1beta1.KubeletX509Authentication{ClientCAFile: ""},
					Webhook: v1beta1.KubeletWebhookAuthentication{
						Enabled:  ptr.To(false),
						CacheTTL: metav1.Duration{Duration: 2 * time.Minute},
					},
					Anonymous: v1beta1.KubeletAnonymousAuthentication{Enabled: ptr.To(false)},
				},
				Authorization: v1beta1.KubeletAuthorization{
					Mode: v1beta1.KubeletAuthorizationModeWebhook,
					Webhook: v1beta1.KubeletWebhookAuthorization{
						CacheAuthorizedTTL:   metav1.Duration{Duration: 5 * time.Minute},
						CacheUnauthorizedTTL: metav1.Duration{Duration: 30 * time.Second},
					},
				},
				RegistryPullQPS:                           ptr.To[int32](0),
				RegistryBurst:                             10,
				EventRecordQPS:                            ptr.To[int32](0),
				EventBurst:                                100,
				EnableDebuggingHandlers:                   ptr.To(false),
				HealthzPort:                               ptr.To[int32](0),
				HealthzBindAddress:                        "127.0.0.1",
				OOMScoreAdj:                               ptr.To[int32](0),
				ClusterDNS:                                []string{},
				StreamingConnectionIdleTimeout:            metav1.Duration{Duration: 4 * time.Hour},
				NodeStatusUpdateFrequency:                 metav1.Duration{Duration: 10 * time.Second},
				NodeStatusReportFrequency:                 metav1.Duration{Duration: 5 * time.Minute},
				NodeLeaseDurationSeconds:                  40,
				ContainerRuntimeEndpoint:                  "unix:///run/containerd/containerd.sock",
				ImageMinimumGCAge:                         metav1.Duration{Duration: 2 * time.Minute},
				ImageGCHighThresholdPercent:               ptr.To[int32](0),
				ImageGCLowThresholdPercent:                ptr.To[int32](0),
				ImagePullCredentialsVerificationPolicy:    "NeverVerifyPreloadedImages",
				VolumeStatsAggPeriod:                      metav1.Duration{Duration: time.Minute},
				CgroupsPerQOS:                             ptr.To(false),
				CgroupDriver:                              "cgroupfs",
				CPUManagerPolicy:                          "none",
				CPUManagerPolicyOptions:                   map[string]string{},
				CPUManagerReconcilePeriod:                 metav1.Duration{Duration: 10 * time.Second},
				MemoryManagerPolicy:                       v1beta1.NoneMemoryManagerPolicy,
				TopologyManagerPolicy:                     v1beta1.NoneTopologyManagerPolicy,
				TopologyManagerScope:                      v1beta1.ContainerTopologyManagerScope,
				QOSReserved:                               map[string]string{},
				RuntimeRequestTimeout:                     metav1.Duration{Duration: 2 * time.Minute},
				HairpinMode:                               v1beta1.PromiscuousBridge,
				MaxPods:                                   110,
				PodPidsLimit:                              ptr.To[int64](0),
				ResolverConfig:                            ptr.To(""),
				CPUCFSQuota:                               ptr.To(false),
				CPUCFSQuotaPeriod:                         &zeroDuration,
				NodeStatusMaxImages:                       ptr.To[int32](0),
				MaxOpenFiles:                              1000000,
				ContentType:                               "application/vnd.kubernetes.protobuf",
				KubeAPIQPS:                                ptr.To[int32](0),
				KubeAPIBurst:                              100,
				SerializeImagePulls:                       ptr.To(false),
				MaxParallelImagePulls:                     nil,
				EvictionHard:                              map[string]string{},
				EvictionSoft:                              map[string]string{},
				EvictionSoftGracePeriod:                   map[string]string{},
				EvictionPressureTransitionPeriod:          metav1.Duration{Duration: 5 * time.Minute},
				EvictionMinimumReclaim:                    map[string]string{},
				MergeDefaultEvictionSettings:              ptr.To(false),
				EnableControllerAttachDetach:              ptr.To(false),
				MakeIPTablesUtilChains:                    ptr.To(false),
				IPTablesMasqueradeBit:                     ptr.To[int32](0),
				IPTablesDropBit:                           ptr.To[int32](0),
				FeatureGates:                              map[string]bool{},
				FailSwapOn:                                ptr.To(false),
				MemorySwap:                                v1beta1.MemorySwapConfiguration{SwapBehavior: ""},
				ContainerLogMaxSize:                       "10Mi",
				ContainerLogMaxFiles:                      ptr.To[int32](0),
				ContainerLogMaxWorkers:                    ptr.To[int32](1),
				ContainerLogMonitorInterval:               &metav1.Duration{Duration: 10 * time.Second},
				ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
				SystemReserved:                            map[string]string{},
				KubeReserved:                              map[string]string{},
				EnforceNodeAllocatable:                    []string{},
				AllowedUnsafeSysctls:                      []string{},
				VolumePluginDir:                           DefaultVolumePluginDir,
				Logging: logsapi.LoggingConfiguration{
					Format:         "text",
					FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
				},
				EnableSystemLogHandler:        ptr.To(false),
				ReservedMemory:                []v1beta1.MemoryReservation{},
				EnableProfilingHandler:        ptr.To(false),
				EnableDebugFlagsHandler:       ptr.To(false),
				SeccompDefault:                ptr.To(false),
				FailCgroupV1:                  ptr.To(true),
				MemoryThrottlingFactor:        ptr.To[float64](0),
				MemoryReservationPolicy:       v1beta1.NoneMemoryReservationPolicy,
				RegisterNode:                  ptr.To(false),
				LocalStorageCapacityIsolation: ptr.To(false),
				PodLogsDir:                    DefaultPodLogsDir,
				SingleProcessOOMKill:          ptr.To(false),
				CrashLoopBackOff: v1beta1.CrashLoopBackOffConfig{
					MaxContainerRestartPeriod: &metav1.Duration{Duration: MaxContainerBackOff},
				},
			},
		},
		{
			"all positive",
			&v1beta1.KubeletConfiguration{
				FeatureGates:       map[string]bool{"KubeletCrashLoopBackOffMax": true},
				EnableServer:       ptr.To(true),
				StaticPodPath:      "static/pod/path",
				SyncFrequency:      metav1.Duration{Duration: 60 * time.Second},
				FileCheckFrequency: metav1.Duration{Duration: 60 * time.Second},
				HTTPCheckFrequency: metav1.Duration{Duration: 60 * time.Second},
				StaticPodURL:       "static-pod-url",
				StaticPodURLHeader: map[string][]string{"Static-Pod-URL-Header": {"true"}},
				Address:            "192.168.1.2",
				Port:               10250,
				ReadOnlyPort:       10251,
				TLSCertFile:        "tls-cert-file",
				TLSPrivateKeyFile:  "tls-private-key-file",
				TLSCipherSuites:    []string{"TLS_AES_128_GCM_SHA256"},
				TLSMinVersion:      "1.3",
				RotateCertificates: true,
				ServerTLSBootstrap: true,
				Authentication: v1beta1.KubeletAuthentication{
					X509: v1beta1.KubeletX509Authentication{ClientCAFile: "client-ca-file"},
					Webhook: v1beta1.KubeletWebhookAuthentication{
						Enabled:  ptr.To(true),
						CacheTTL: metav1.Duration{Duration: 60 * time.Second},
					},
					Anonymous: v1beta1.KubeletAnonymousAuthentication{Enabled: ptr.To(true)},
				},
				Authorization: v1beta1.KubeletAuthorization{
					Mode: v1beta1.KubeletAuthorizationModeAlwaysAllow,
					Webhook: v1beta1.KubeletWebhookAuthorization{
						CacheAuthorizedTTL:   metav1.Duration{Duration: 60 * time.Second},
						CacheUnauthorizedTTL: metav1.Duration{Duration: 60 * time.Second},
					},
				},
				RegistryPullQPS:                        ptr.To[int32](1),
				RegistryBurst:                          1,
				EventRecordQPS:                         ptr.To[int32](1),
				EventBurst:                             1,
				EnableDebuggingHandlers:                ptr.To(true),
				EnableContentionProfiling:              true,
				HealthzPort:                            ptr.To[int32](1),
				HealthzBindAddress:                     "127.0.0.2",
				OOMScoreAdj:                            ptr.To[int32](1),
				ClusterDomain:                          "cluster-domain",
				ClusterDNS:                             []string{"192.168.1.3"},
				StreamingConnectionIdleTimeout:         metav1.Duration{Duration: 60 * time.Second},
				NodeStatusUpdateFrequency:              metav1.Duration{Duration: 60 * time.Second},
				NodeStatusReportFrequency:              metav1.Duration{Duration: 60 * time.Second},
				NodeLeaseDurationSeconds:               1,
				ContainerRuntimeEndpoint:               "unix:///run/containerd/containerd.sock",
				ImageMinimumGCAge:                      metav1.Duration{Duration: 60 * time.Second},
				ImageGCHighThresholdPercent:            ptr.To[int32](1),
				ImageGCLowThresholdPercent:             ptr.To[int32](1),
				ImagePullCredentialsVerificationPolicy: "AlwaysVerify",
				PreloadedImagesVerificationAllowlist:   []string{"test.test/repo/image"},
				VolumeStatsAggPeriod:                   metav1.Duration{Duration: 60 * time.Second},
				KubeletCgroups:                         "kubelet-cgroup",
				SystemCgroups:                          "system-cgroup",
				CgroupRoot:                             "root-cgroup",
				CgroupsPerQOS:                          ptr.To(true),
				CgroupDriver:                           "systemd",
				CPUManagerPolicy:                       "cpu-manager-policy",
				CPUManagerPolicyOptions:                map[string]string{"key": "value"},
				CPUManagerReconcilePeriod:              metav1.Duration{Duration: 60 * time.Second},
				MemoryManagerPolicy:                    v1beta1.StaticMemoryManagerPolicy,
				TopologyManagerPolicy:                  v1beta1.RestrictedTopologyManagerPolicy,
				TopologyManagerScope:                   v1beta1.PodTopologyManagerScope,
				QOSReserved:                            map[string]string{"memory": "10%"},
				RuntimeRequestTimeout:                  metav1.Duration{Duration: 60 * time.Second},
				HairpinMode:                            v1beta1.HairpinVeth,
				MaxPods:                                1,
				PodCIDR:                                "192.168.1.0/24",
				PodPidsLimit:                           ptr.To[int64](1),
				ResolverConfig:                         ptr.To("resolver-config"),
				RunOnce:                                true,
				CPUCFSQuota:                            ptr.To(true),
				CPUCFSQuotaPeriod:                      &metav1.Duration{Duration: 60 * time.Second},
				NodeStatusMaxImages:                    ptr.To[int32](1),
				MaxOpenFiles:                           1,
				ContentType:                            "application/protobuf",
				KubeAPIQPS:                             ptr.To[int32](1),
				KubeAPIBurst:                           1,
				SerializeImagePulls:                    ptr.To(true),
				MaxParallelImagePulls:                  ptr.To[int32](5),
				EvictionHard: map[string]string{
					"memory.available":  "1Mi",
					"nodefs.available":  "1%",
					"imagefs.available": "1%",
				},
				EvictionSoft: map[string]string{
					"memory.available":  "2Mi",
					"nodefs.available":  "2%",
					"imagefs.available": "2%",
				},
				EvictionSoftGracePeriod: map[string]string{
					"memory.available":  "60s",
					"nodefs.available":  "60s",
					"imagefs.available": "60s",
				},
				EvictionPressureTransitionPeriod: metav1.Duration{Duration: 60 * time.Second},
				EvictionMaxPodGracePeriod:        1,
				EvictionMinimumReclaim: map[string]string{
					"imagefs.available": "1Gi",
				},
				MergeDefaultEvictionSettings:              ptr.To(true),
				PodsPerCore:                               1,
				EnableControllerAttachDetach:              ptr.To(true),
				ProtectKernelDefaults:                     true,
				MakeIPTablesUtilChains:                    ptr.To(true),
				IPTablesMasqueradeBit:                     ptr.To[int32](1),
				IPTablesDropBit:                           ptr.To[int32](1),
				FailSwapOn:                                ptr.To(true),
				MemorySwap:                                v1beta1.MemorySwapConfiguration{SwapBehavior: "NoSwap"},
				ContainerLogMaxSize:                       "1Mi",
				ContainerLogMaxFiles:                      ptr.To[int32](1),
				ContainerLogMaxWorkers:                    ptr.To[int32](1),
				ContainerLogMonitorInterval:               &metav1.Duration{Duration: 10 * time.Second},
				ConfigMapAndSecretChangeDetectionStrategy: v1beta1.TTLCacheChangeDetectionStrategy,
				SystemReserved: map[string]string{
					"memory": "1Gi",
				},
				KubeReserved: map[string]string{
					"memory": "1Gi",
				},
				ReservedSystemCPUs:          "0,1",
				ShowHiddenMetricsForVersion: "1.16",
				SystemReservedCgroup:        "system-reserved-cgroup",
				KubeReservedCgroup:          "kube-reserved-cgroup",
				EnforceNodeAllocatable:      []string{"system-reserved"},
				AllowedUnsafeSysctls:        []string{"kernel.msg*"},
				VolumePluginDir:             "volume-plugin-dir",
				ProviderID:                  "provider-id",
				KernelMemcgNotification:     true,
				Logging: logsapi.LoggingConfiguration{
					Format:         "json",
					FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
				},
				EnableSystemLogHandler:          ptr.To(true),
				ShutdownGracePeriod:             metav1.Duration{Duration: 60 * time.Second},
				ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: 60 * time.Second},
				ReservedMemory: []v1beta1.MemoryReservation{
					{
						NumaNode: 1,
						Limits:   v1.ResourceList{v1.ResourceMemory: resource.MustParse("1Gi")},
					},
				},
				EnableProfilingHandler:        ptr.To(true),
				EnableDebugFlagsHandler:       ptr.To(true),
				SeccompDefault:                ptr.To(true),
				FailCgroupV1:                  ptr.To(true),
				MemoryThrottlingFactor:        ptr.To[float64](1),
				MemoryReservationPolicy:       v1beta1.NoneMemoryReservationPolicy,
				RegisterNode:                  ptr.To(true),
				LocalStorageCapacityIsolation: ptr.To(true),
				PodLogsDir:                    "/custom/path",
				SingleProcessOOMKill:          ptr.To(true),
				CrashLoopBackOff: v1beta1.CrashLoopBackOffConfig{
					MaxContainerRestartPeriod: &metav1.Duration{Duration: 55 * time.Second},
				},
			},
			&v1beta1.KubeletConfiguration{
				FeatureGates:       map[string]bool{"KubeletCrashLoopBackOffMax": true},
				EnableServer:       ptr.To(true),
				StaticPodPath:      "static/pod/path",
				SyncFrequency:      metav1.Duration{Duration: 60 * time.Second},
				FileCheckFrequency: metav1.Duration{Duration: 60 * time.Second},
				HTTPCheckFrequency: metav1.Duration{Duration: 60 * time.Second},
				StaticPodURL:       "static-pod-url",
				StaticPodURLHeader: map[string][]string{"Static-Pod-URL-Header": {"true"}},
				Address:            "192.168.1.2",
				Port:               10250,
				ReadOnlyPort:       10251,
				TLSCertFile:        "tls-cert-file",
				TLSPrivateKeyFile:  "tls-private-key-file",
				TLSCipherSuites:    []string{"TLS_AES_128_GCM_SHA256"},
				TLSMinVersion:      "1.3",
				RotateCertificates: true,
				ServerTLSBootstrap: true,
				Authentication: v1beta1.KubeletAuthentication{
					X509: v1beta1.KubeletX509Authentication{ClientCAFile: "client-ca-file"},
					Webhook: v1beta1.KubeletWebhookAuthentication{
						Enabled:  ptr.To(true),
						CacheTTL: metav1.Duration{Duration: 60 * time.Second},
					},
					Anonymous: v1beta1.KubeletAnonymousAuthentication{Enabled: ptr.To(true)},
				},
				Authorization: v1beta1.KubeletAuthorization{
					Mode: v1beta1.KubeletAuthorizationModeAlwaysAllow,
					Webhook: v1beta1.KubeletWebhookAuthorization{
						CacheAuthorizedTTL:   metav1.Duration{Duration: 60 * time.Second},
						CacheUnauthorizedTTL: metav1.Duration{Duration: 60 * time.Second},
					},
				},
				RegistryPullQPS:                        ptr.To[int32](1),
				RegistryBurst:                          1,
				EventRecordQPS:                         ptr.To[int32](1),
				EventBurst:                             1,
				EnableDebuggingHandlers:                ptr.To(true),
				EnableContentionProfiling:              true,
				HealthzPort:                            ptr.To[int32](1),
				HealthzBindAddress:                     "127.0.0.2",
				OOMScoreAdj:                            ptr.To[int32](1),
				ClusterDomain:                          "cluster-domain",
				ClusterDNS:                             []string{"192.168.1.3"},
				StreamingConnectionIdleTimeout:         metav1.Duration{Duration: 60 * time.Second},
				NodeStatusUpdateFrequency:              metav1.Duration{Duration: 60 * time.Second},
				NodeStatusReportFrequency:              metav1.Duration{Duration: 60 * time.Second},
				NodeLeaseDurationSeconds:               1,
				ContainerRuntimeEndpoint:               "unix:///run/containerd/containerd.sock",
				ImageMinimumGCAge:                      metav1.Duration{Duration: 60 * time.Second},
				ImageGCHighThresholdPercent:            ptr.To[int32](1),
				ImageGCLowThresholdPercent:             ptr.To[int32](1),
				ImagePullCredentialsVerificationPolicy: "AlwaysVerify",
				PreloadedImagesVerificationAllowlist:   []string{"test.test/repo/image"},
				VolumeStatsAggPeriod:                   metav1.Duration{Duration: 60 * time.Second},
				KubeletCgroups:                         "kubelet-cgroup",
				SystemCgroups:                          "system-cgroup",
				CgroupRoot:                             "root-cgroup",
				CgroupsPerQOS:                          ptr.To(true),
				CgroupDriver:                           "systemd",
				CPUManagerPolicy:                       "cpu-manager-policy",
				CPUManagerPolicyOptions:                map[string]string{"key": "value"},
				CPUManagerReconcilePeriod:              metav1.Duration{Duration: 60 * time.Second},
				MemoryManagerPolicy:                    v1beta1.StaticMemoryManagerPolicy,
				TopologyManagerPolicy:                  v1beta1.RestrictedTopologyManagerPolicy,
				TopologyManagerScope:                   v1beta1.PodTopologyManagerScope,
				QOSReserved:                            map[string]string{"memory": "10%"},
				RuntimeRequestTimeout:                  metav1.Duration{Duration: 60 * time.Second},
				HairpinMode:                            v1beta1.HairpinVeth,
				MaxPods:                                1,
				PodCIDR:                                "192.168.1.0/24",
				PodPidsLimit:                           ptr.To[int64](1),
				ResolverConfig:                         ptr.To("resolver-config"),
				RunOnce:                                true,
				CPUCFSQuota:                            ptr.To(true),
				CPUCFSQuotaPeriod:                      &metav1.Duration{Duration: 60 * time.Second},
				NodeStatusMaxImages:                    ptr.To[int32](1),
				MaxOpenFiles:                           1,
				ContentType:                            "application/protobuf",
				KubeAPIQPS:                             ptr.To[int32](1),
				KubeAPIBurst:                           1,
				SerializeImagePulls:                    ptr.To(true),
				MaxParallelImagePulls:                  ptr.To[int32](5),
				EvictionHard: map[string]string{
					"memory.available":  "1Mi",
					"nodefs.available":  "1%",
					"imagefs.available": "1%",
				},
				EvictionSoft: map[string]string{
					"memory.available":  "2Mi",
					"nodefs.available":  "2%",
					"imagefs.available": "2%",
				},
				EvictionSoftGracePeriod: map[string]string{
					"memory.available":  "60s",
					"nodefs.available":  "60s",
					"imagefs.available": "60s",
				},
				EvictionPressureTransitionPeriod: metav1.Duration{Duration: 60 * time.Second},
				EvictionMaxPodGracePeriod:        1,
				EvictionMinimumReclaim: map[string]string{
					"imagefs.available": "1Gi",
				},
				PodsPerCore:                               1,
				EnableControllerAttachDetach:              ptr.To(true),
				ProtectKernelDefaults:                     true,
				MergeDefaultEvictionSettings:              ptr.To(true),
				MakeIPTablesUtilChains:                    ptr.To(true),
				IPTablesMasqueradeBit:                     ptr.To[int32](1),
				IPTablesDropBit:                           ptr.To[int32](1),
				FailSwapOn:                                ptr.To(true),
				MemorySwap:                                v1beta1.MemorySwapConfiguration{SwapBehavior: "NoSwap"},
				ContainerLogMaxSize:                       "1Mi",
				ContainerLogMaxFiles:                      ptr.To[int32](1),
				ContainerLogMaxWorkers:                    ptr.To[int32](1),
				ContainerLogMonitorInterval:               &metav1.Duration{Duration: 10 * time.Second},
				ConfigMapAndSecretChangeDetectionStrategy: v1beta1.TTLCacheChangeDetectionStrategy,
				SystemReserved: map[string]string{
					"memory": "1Gi",
				},
				KubeReserved: map[string]string{
					"memory": "1Gi",
				},
				ReservedSystemCPUs:          "0,1",
				ShowHiddenMetricsForVersion: "1.16",
				SystemReservedCgroup:        "system-reserved-cgroup",
				KubeReservedCgroup:          "kube-reserved-cgroup",
				EnforceNodeAllocatable:      []string{"system-reserved"},
				AllowedUnsafeSysctls:        []string{"kernel.msg*"},
				VolumePluginDir:             "volume-plugin-dir",
				ProviderID:                  "provider-id",
				KernelMemcgNotification:     true,
				Logging: logsapi.LoggingConfiguration{
					Format:         "json",
					FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
				},
				EnableSystemLogHandler:          ptr.To(true),
				ShutdownGracePeriod:             metav1.Duration{Duration: 60 * time.Second},
				ShutdownGracePeriodCriticalPods: metav1.Duration{Duration: 60 * time.Second},
				ReservedMemory: []v1beta1.MemoryReservation{
					{
						NumaNode: 1,
						Limits:   v1.ResourceList{v1.ResourceMemory: resource.MustParse("1Gi")},
					},
				},
				EnableProfilingHandler:        ptr.To(true),
				EnableDebugFlagsHandler:       ptr.To(true),
				SeccompDefault:                ptr.To(true),
				FailCgroupV1:                  ptr.To(true),
				MemoryThrottlingFactor:        ptr.To[float64](1),
				MemoryReservationPolicy:       v1beta1.NoneMemoryReservationPolicy,
				RegisterNode:                  ptr.To(true),
				LocalStorageCapacityIsolation: ptr.To(true),
				PodLogsDir:                    "/custom/path",
				SingleProcessOOMKill:          ptr.To(true),
				CrashLoopBackOff: v1beta1.CrashLoopBackOffConfig{
					MaxContainerRestartPeriod: &metav1.Duration{Duration: 55 * time.Second},
				},
			},
		},
		{
			"NodeStatusUpdateFrequency is not zero",
			&v1beta1.KubeletConfiguration{
				NodeStatusUpdateFrequency: metav1.Duration{Duration: 1 * time.Minute},
			},
			&v1beta1.KubeletConfiguration{
				EnableServer:       ptr.To(true),
				SyncFrequency:      metav1.Duration{Duration: 1 * time.Minute},
				FileCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				HTTPCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				Address:            "0.0.0.0",
				Port:               ports.KubeletPort,
				Authentication: v1beta1.KubeletAuthentication{
					Anonymous: v1beta1.KubeletAnonymousAuthentication{Enabled: ptr.To(false)},
					Webhook: v1beta1.KubeletWebhookAuthentication{
						Enabled:  ptr.To(true),
						CacheTTL: metav1.Duration{Duration: 2 * time.Minute},
					},
				},
				Authorization: v1beta1.KubeletAuthorization{
					Mode: v1beta1.KubeletAuthorizationModeWebhook,
					Webhook: v1beta1.KubeletWebhookAuthorization{
						CacheAuthorizedTTL:   metav1.Duration{Duration: 5 * time.Minute},
						CacheUnauthorizedTTL: metav1.Duration{Duration: 30 * time.Second},
					},
				},
				RegistryPullQPS:                           ptr.To[int32](5),
				RegistryBurst:                             10,
				EventRecordQPS:                            ptr.To[int32](50),
				EventBurst:                                100,
				EnableDebuggingHandlers:                   ptr.To(true),
				HealthzPort:                               ptr.To[int32](10248),
				HealthzBindAddress:                        "127.0.0.1",
				OOMScoreAdj:                               ptr.To(int32(qos.KubeletOOMScoreAdj)),
				StreamingConnectionIdleTimeout:            metav1.Duration{Duration: 4 * time.Hour},
				NodeStatusUpdateFrequency:                 metav1.Duration{Duration: 1 * time.Minute},
				NodeStatusReportFrequency:                 metav1.Duration{Duration: 1 * time.Minute},
				NodeLeaseDurationSeconds:                  40,
				ContainerRuntimeEndpoint:                  "unix:///run/containerd/containerd.sock",
				ImageMinimumGCAge:                         metav1.Duration{Duration: 2 * time.Minute},
				ImageGCHighThresholdPercent:               ptr.To[int32](85),
				ImageGCLowThresholdPercent:                ptr.To[int32](80),
				ImagePullCredentialsVerificationPolicy:    "NeverVerifyPreloadedImages",
				VolumeStatsAggPeriod:                      metav1.Duration{Duration: time.Minute},
				CgroupsPerQOS:                             ptr.To(true),
				CgroupDriver:                              "cgroupfs",
				CPUManagerPolicy:                          "none",
				CPUManagerReconcilePeriod:                 metav1.Duration{Duration: 10 * time.Second},
				MemoryManagerPolicy:                       v1beta1.NoneMemoryManagerPolicy,
				TopologyManagerPolicy:                     v1beta1.NoneTopologyManagerPolicy,
				TopologyManagerScope:                      v1beta1.ContainerTopologyManagerScope,
				RuntimeRequestTimeout:                     metav1.Duration{Duration: 2 * time.Minute},
				HairpinMode:                               v1beta1.PromiscuousBridge,
				MaxPods:                                   110,
				PodPidsLimit:                              ptr.To[int64](-1),
				ResolverConfig:                            ptr.To(kubetypes.ResolvConfDefault),
				CPUCFSQuota:                               ptr.To(true),
				CPUCFSQuotaPeriod:                         &metav1.Duration{Duration: 100 * time.Millisecond},
				NodeStatusMaxImages:                       ptr.To[int32](50),
				MaxOpenFiles:                              1000000,
				ContentType:                               "application/vnd.kubernetes.protobuf",
				KubeAPIQPS:                                ptr.To[int32](50),
				KubeAPIBurst:                              100,
				SerializeImagePulls:                       ptr.To(true),
				MaxParallelImagePulls:                     nil,
				EvictionHard:                              nil,
				EvictionPressureTransitionPeriod:          metav1.Duration{Duration: 5 * time.Minute},
				MergeDefaultEvictionSettings:              ptr.To(false),
				EnableControllerAttachDetach:              ptr.To(true),
				MakeIPTablesUtilChains:                    ptr.To(true),
				IPTablesMasqueradeBit:                     ptr.To[int32](DefaultIPTablesMasqueradeBit),
				IPTablesDropBit:                           ptr.To[int32](DefaultIPTablesDropBit),
				FailSwapOn:                                ptr.To(true),
				ContainerLogMaxSize:                       "10Mi",
				ContainerLogMaxFiles:                      ptr.To[int32](5),
				ContainerLogMaxWorkers:                    ptr.To[int32](1),
				ContainerLogMonitorInterval:               &metav1.Duration{Duration: 10 * time.Second},
				ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
				EnforceNodeAllocatable:                    DefaultNodeAllocatableEnforcement,
				VolumePluginDir:                           DefaultVolumePluginDir,
				Logging: logsapi.LoggingConfiguration{
					Format:         "text",
					FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
				},
				EnableSystemLogHandler:        ptr.To(true),
				EnableProfilingHandler:        ptr.To(true),
				EnableDebugFlagsHandler:       ptr.To(true),
				SeccompDefault:                ptr.To(false),
				FailCgroupV1:                  ptr.To(true),
				MemoryThrottlingFactor:        ptr.To(DefaultMemoryThrottlingFactor),
				MemoryReservationPolicy:       v1beta1.NoneMemoryReservationPolicy,
				RegisterNode:                  ptr.To(true),
				LocalStorageCapacityIsolation: ptr.To(true),
				PodLogsDir:                    DefaultPodLogsDir,
				SingleProcessOOMKill:          nil,
				CrashLoopBackOff: v1beta1.CrashLoopBackOffConfig{
					MaxContainerRestartPeriod: &metav1.Duration{Duration: MaxContainerBackOff},
				},
			},
		},
		{
			"SerializeImagePull defaults to false when MaxParallelImagePulls is larger than 1",
			&v1beta1.KubeletConfiguration{
				MaxParallelImagePulls: ptr.To[int32](5),
			},
			&v1beta1.KubeletConfiguration{
				EnableServer:       ptr.To(true),
				SyncFrequency:      metav1.Duration{Duration: 1 * time.Minute},
				FileCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				HTTPCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				Address:            "0.0.0.0",
				Port:               ports.KubeletPort,
				Authentication: v1beta1.KubeletAuthentication{
					Anonymous: v1beta1.KubeletAnonymousAuthentication{Enabled: ptr.To(false)},
					Webhook: v1beta1.KubeletWebhookAuthentication{
						Enabled:  ptr.To(true),
						CacheTTL: metav1.Duration{Duration: 2 * time.Minute},
					},
				},
				Authorization: v1beta1.KubeletAuthorization{
					Mode: v1beta1.KubeletAuthorizationModeWebhook,
					Webhook: v1beta1.KubeletWebhookAuthorization{
						CacheAuthorizedTTL:   metav1.Duration{Duration: 5 * time.Minute},
						CacheUnauthorizedTTL: metav1.Duration{Duration: 30 * time.Second},
					},
				},
				RegistryPullQPS:                           ptr.To[int32](5),
				RegistryBurst:                             10,
				EventRecordQPS:                            ptr.To[int32](50),
				EventBurst:                                100,
				EnableDebuggingHandlers:                   ptr.To(true),
				HealthzPort:                               ptr.To[int32](10248),
				HealthzBindAddress:                        "127.0.0.1",
				OOMScoreAdj:                               ptr.To(int32(qos.KubeletOOMScoreAdj)),
				StreamingConnectionIdleTimeout:            metav1.Duration{Duration: 4 * time.Hour},
				NodeStatusUpdateFrequency:                 metav1.Duration{Duration: 10 * time.Second},
				NodeStatusReportFrequency:                 metav1.Duration{Duration: 5 * time.Minute},
				NodeLeaseDurationSeconds:                  40,
				ContainerRuntimeEndpoint:                  "unix:///run/containerd/containerd.sock",
				ImageMinimumGCAge:                         metav1.Duration{Duration: 2 * time.Minute},
				ImageGCHighThresholdPercent:               ptr.To[int32](85),
				ImageGCLowThresholdPercent:                ptr.To[int32](80),
				ImagePullCredentialsVerificationPolicy:    "NeverVerifyPreloadedImages",
				VolumeStatsAggPeriod:                      metav1.Duration{Duration: time.Minute},
				CgroupsPerQOS:                             ptr.To(true),
				CgroupDriver:                              "cgroupfs",
				CPUManagerPolicy:                          "none",
				CPUManagerReconcilePeriod:                 metav1.Duration{Duration: 10 * time.Second},
				MemoryManagerPolicy:                       v1beta1.NoneMemoryManagerPolicy,
				TopologyManagerPolicy:                     v1beta1.NoneTopologyManagerPolicy,
				TopologyManagerScope:                      v1beta1.ContainerTopologyManagerScope,
				RuntimeRequestTimeout:                     metav1.Duration{Duration: 2 * time.Minute},
				HairpinMode:                               v1beta1.PromiscuousBridge,
				MaxPods:                                   110,
				PodPidsLimit:                              ptr.To[int64](-1),
				ResolverConfig:                            ptr.To(kubetypes.ResolvConfDefault),
				CPUCFSQuota:                               ptr.To(true),
				CPUCFSQuotaPeriod:                         &metav1.Duration{Duration: 100 * time.Millisecond},
				NodeStatusMaxImages:                       ptr.To[int32](50),
				MaxOpenFiles:                              1000000,
				ContentType:                               "application/vnd.kubernetes.protobuf",
				KubeAPIQPS:                                ptr.To[int32](50),
				KubeAPIBurst:                              100,
				SerializeImagePulls:                       ptr.To(false),
				MaxParallelImagePulls:                     ptr.To[int32](5),
				EvictionHard:                              nil,
				EvictionPressureTransitionPeriod:          metav1.Duration{Duration: 5 * time.Minute},
				MergeDefaultEvictionSettings:              ptr.To(false),
				EnableControllerAttachDetach:              ptr.To(true),
				MakeIPTablesUtilChains:                    ptr.To(true),
				IPTablesMasqueradeBit:                     ptr.To[int32](DefaultIPTablesMasqueradeBit),
				IPTablesDropBit:                           ptr.To[int32](DefaultIPTablesDropBit),
				FailSwapOn:                                ptr.To(true),
				ContainerLogMaxSize:                       "10Mi",
				ContainerLogMaxFiles:                      ptr.To[int32](5),
				ContainerLogMaxWorkers:                    ptr.To[int32](1),
				ContainerLogMonitorInterval:               &metav1.Duration{Duration: 10 * time.Second},
				ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
				EnforceNodeAllocatable:                    DefaultNodeAllocatableEnforcement,
				VolumePluginDir:                           DefaultVolumePluginDir,
				Logging: logsapi.LoggingConfiguration{
					Format:         "text",
					FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
				},
				EnableSystemLogHandler:        ptr.To(true),
				EnableProfilingHandler:        ptr.To(true),
				EnableDebugFlagsHandler:       ptr.To(true),
				SeccompDefault:                ptr.To(false),
				FailCgroupV1:                  ptr.To(true),
				MemoryThrottlingFactor:        ptr.To(DefaultMemoryThrottlingFactor),
				MemoryReservationPolicy:       v1beta1.NoneMemoryReservationPolicy,
				RegisterNode:                  ptr.To(true),
				LocalStorageCapacityIsolation: ptr.To(true),
				PodLogsDir:                    DefaultPodLogsDir,
				SingleProcessOOMKill:          nil,
				CrashLoopBackOff: v1beta1.CrashLoopBackOffConfig{
					MaxContainerRestartPeriod: &metav1.Duration{Duration: MaxContainerBackOff},
				},
			},
		},
		{
			"SerializeImagePull defaults to true when MaxParallelImagePulls is set to 1",
			&v1beta1.KubeletConfiguration{
				MaxParallelImagePulls: ptr.To[int32](1),
			},
			&v1beta1.KubeletConfiguration{
				EnableServer:       ptr.To(true),
				SyncFrequency:      metav1.Duration{Duration: 1 * time.Minute},
				FileCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				HTTPCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				Address:            "0.0.0.0",
				Port:               ports.KubeletPort,
				Authentication: v1beta1.KubeletAuthentication{
					Anonymous: v1beta1.KubeletAnonymousAuthentication{Enabled: ptr.To(false)},
					Webhook: v1beta1.KubeletWebhookAuthentication{
						Enabled:  ptr.To(true),
						CacheTTL: metav1.Duration{Duration: 2 * time.Minute},
					},
				},
				Authorization: v1beta1.KubeletAuthorization{
					Mode: v1beta1.KubeletAuthorizationModeWebhook,
					Webhook: v1beta1.KubeletWebhookAuthorization{
						CacheAuthorizedTTL:   metav1.Duration{Duration: 5 * time.Minute},
						CacheUnauthorizedTTL: metav1.Duration{Duration: 30 * time.Second},
					},
				},
				RegistryPullQPS:                           ptr.To[int32](5),
				RegistryBurst:                             10,
				EventRecordQPS:                            ptr.To[int32](50),
				EventBurst:                                100,
				EnableDebuggingHandlers:                   ptr.To(true),
				HealthzPort:                               ptr.To[int32](10248),
				HealthzBindAddress:                        "127.0.0.1",
				OOMScoreAdj:                               ptr.To(int32(qos.KubeletOOMScoreAdj)),
				StreamingConnectionIdleTimeout:            metav1.Duration{Duration: 4 * time.Hour},
				NodeStatusUpdateFrequency:                 metav1.Duration{Duration: 10 * time.Second},
				NodeStatusReportFrequency:                 metav1.Duration{Duration: 5 * time.Minute},
				NodeLeaseDurationSeconds:                  40,
				ContainerRuntimeEndpoint:                  "unix:///run/containerd/containerd.sock",
				ImageMinimumGCAge:                         metav1.Duration{Duration: 2 * time.Minute},
				ImageGCHighThresholdPercent:               ptr.To[int32](85),
				ImageGCLowThresholdPercent:                ptr.To[int32](80),
				ImagePullCredentialsVerificationPolicy:    "NeverVerifyPreloadedImages",
				VolumeStatsAggPeriod:                      metav1.Duration{Duration: time.Minute},
				CgroupsPerQOS:                             ptr.To(true),
				CgroupDriver:                              "cgroupfs",
				CPUManagerPolicy:                          "none",
				CPUManagerReconcilePeriod:                 metav1.Duration{Duration: 10 * time.Second},
				MemoryManagerPolicy:                       v1beta1.NoneMemoryManagerPolicy,
				TopologyManagerPolicy:                     v1beta1.NoneTopologyManagerPolicy,
				TopologyManagerScope:                      v1beta1.ContainerTopologyManagerScope,
				RuntimeRequestTimeout:                     metav1.Duration{Duration: 2 * time.Minute},
				HairpinMode:                               v1beta1.PromiscuousBridge,
				MaxPods:                                   110,
				PodPidsLimit:                              ptr.To[int64](-1),
				ResolverConfig:                            ptr.To(kubetypes.ResolvConfDefault),
				CPUCFSQuota:                               ptr.To(true),
				CPUCFSQuotaPeriod:                         &metav1.Duration{Duration: 100 * time.Millisecond},
				NodeStatusMaxImages:                       ptr.To[int32](50),
				MaxOpenFiles:                              1000000,
				ContentType:                               "application/vnd.kubernetes.protobuf",
				KubeAPIQPS:                                ptr.To[int32](50),
				KubeAPIBurst:                              100,
				SerializeImagePulls:                       ptr.To(true),
				MaxParallelImagePulls:                     ptr.To[int32](1),
				EvictionHard:                              nil,
				EvictionPressureTransitionPeriod:          metav1.Duration{Duration: 5 * time.Minute},
				MergeDefaultEvictionSettings:              ptr.To(false),
				EnableControllerAttachDetach:              ptr.To(true),
				MakeIPTablesUtilChains:                    ptr.To(true),
				IPTablesMasqueradeBit:                     ptr.To[int32](DefaultIPTablesMasqueradeBit),
				IPTablesDropBit:                           ptr.To[int32](DefaultIPTablesDropBit),
				FailSwapOn:                                ptr.To(true),
				ContainerLogMaxSize:                       "10Mi",
				ContainerLogMaxFiles:                      ptr.To[int32](5),
				ContainerLogMaxWorkers:                    ptr.To[int32](1),
				ContainerLogMonitorInterval:               &metav1.Duration{Duration: 10 * time.Second},
				ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
				EnforceNodeAllocatable:                    DefaultNodeAllocatableEnforcement,
				VolumePluginDir:                           DefaultVolumePluginDir,
				Logging: logsapi.LoggingConfiguration{
					Format:         "text",
					FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
				},
				EnableSystemLogHandler:        ptr.To(true),
				EnableProfilingHandler:        ptr.To(true),
				EnableDebugFlagsHandler:       ptr.To(true),
				SeccompDefault:                ptr.To(false),
				FailCgroupV1:                  ptr.To(true),
				MemoryThrottlingFactor:        ptr.To(DefaultMemoryThrottlingFactor),
				MemoryReservationPolicy:       v1beta1.NoneMemoryReservationPolicy,
				RegisterNode:                  ptr.To(true),
				LocalStorageCapacityIsolation: ptr.To(true),
				PodLogsDir:                    DefaultPodLogsDir,
				CrashLoopBackOff: v1beta1.CrashLoopBackOffConfig{
					MaxContainerRestartPeriod: &metav1.Duration{Duration: MaxContainerBackOff},
				},
			},
		},
		{
			"CrashLoopBackOff defaults empty when feature gate disabled",
			&v1beta1.KubeletConfiguration{
				FeatureGates: map[string]bool{"KubeletCrashLoopBackOffMax": false},
			},
			&v1beta1.KubeletConfiguration{
				FeatureGates:       map[string]bool{"KubeletCrashLoopBackOffMax": false},
				EnableServer:       ptr.To(true),
				SyncFrequency:      metav1.Duration{Duration: 1 * time.Minute},
				FileCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				HTTPCheckFrequency: metav1.Duration{Duration: 20 * time.Second},
				Address:            "0.0.0.0",
				Port:               ports.KubeletPort,
				Authentication: v1beta1.KubeletAuthentication{
					Anonymous: v1beta1.KubeletAnonymousAuthentication{Enabled: ptr.To(false)},
					Webhook: v1beta1.KubeletWebhookAuthentication{
						Enabled:  ptr.To(true),
						CacheTTL: metav1.Duration{Duration: 2 * time.Minute},
					},
				},
				Authorization: v1beta1.KubeletAuthorization{
					Mode: v1beta1.KubeletAuthorizationModeWebhook,
					Webhook: v1beta1.KubeletWebhookAuthorization{
						CacheAuthorizedTTL:   metav1.Duration{Duration: 5 * time.Minute},
						CacheUnauthorizedTTL: metav1.Duration{Duration: 30 * time.Second},
					},
				},
				RegistryPullQPS:                           ptr.To[int32](5),
				RegistryBurst:                             10,
				EventRecordQPS:                            ptr.To[int32](50),
				EventBurst:                                100,
				EnableDebuggingHandlers:                   ptr.To(true),
				HealthzPort:                               ptr.To[int32](10248),
				HealthzBindAddress:                        "127.0.0.1",
				OOMScoreAdj:                               ptr.To(int32(qos.KubeletOOMScoreAdj)),
				StreamingConnectionIdleTimeout:            metav1.Duration{Duration: 4 * time.Hour},
				NodeStatusUpdateFrequency:                 metav1.Duration{Duration: 10 * time.Second},
				NodeStatusReportFrequency:                 metav1.Duration{Duration: 5 * time.Minute},
				NodeLeaseDurationSeconds:                  40,
				ContainerRuntimeEndpoint:                  "unix:///run/containerd/containerd.sock",
				ImageMinimumGCAge:                         metav1.Duration{Duration: 2 * time.Minute},
				ImageGCHighThresholdPercent:               ptr.To[int32](85),
				ImageGCLowThresholdPercent:                ptr.To[int32](80),
				ImagePullCredentialsVerificationPolicy:    "NeverVerifyPreloadedImages",
				VolumeStatsAggPeriod:                      metav1.Duration{Duration: time.Minute},
				CgroupsPerQOS:                             ptr.To(true),
				CgroupDriver:                              "cgroupfs",
				CPUManagerPolicy:                          "none",
				CPUManagerReconcilePeriod:                 metav1.Duration{Duration: 10 * time.Second},
				MemoryManagerPolicy:                       v1beta1.NoneMemoryManagerPolicy,
				TopologyManagerPolicy:                     v1beta1.NoneTopologyManagerPolicy,
				TopologyManagerScope:                      v1beta1.ContainerTopologyManagerScope,
				RuntimeRequestTimeout:                     metav1.Duration{Duration: 2 * time.Minute},
				HairpinMode:                               v1beta1.PromiscuousBridge,
				MaxPods:                                   110,
				PodPidsLimit:                              ptr.To[int64](-1),
				ResolverConfig:                            ptr.To(kubetypes.ResolvConfDefault),
				CPUCFSQuota:                               ptr.To(true),
				CPUCFSQuotaPeriod:                         &metav1.Duration{Duration: 100 * time.Millisecond},
				NodeStatusMaxImages:                       ptr.To[int32](50),
				MaxOpenFiles:                              1000000,
				ContentType:                               "application/vnd.kubernetes.protobuf",
				KubeAPIQPS:                                ptr.To[int32](50),
				KubeAPIBurst:                              100,
				SerializeImagePulls:                       ptr.To(true),
				MaxParallelImagePulls:                     nil,
				EvictionHard:                              nil,
				EvictionPressureTransitionPeriod:          metav1.Duration{Duration: 5 * time.Minute},
				MergeDefaultEvictionSettings:              ptr.To(false),
				EnableControllerAttachDetach:              ptr.To(true),
				MakeIPTablesUtilChains:                    ptr.To(true),
				IPTablesMasqueradeBit:                     ptr.To[int32](DefaultIPTablesMasqueradeBit),
				IPTablesDropBit:                           ptr.To[int32](DefaultIPTablesDropBit),
				FailSwapOn:                                ptr.To(true),
				ContainerLogMaxSize:                       "10Mi",
				ContainerLogMaxFiles:                      ptr.To[int32](5),
				ContainerLogMaxWorkers:                    ptr.To[int32](1),
				ContainerLogMonitorInterval:               &metav1.Duration{Duration: 10 * time.Second},
				ConfigMapAndSecretChangeDetectionStrategy: v1beta1.WatchChangeDetectionStrategy,
				EnforceNodeAllocatable:                    DefaultNodeAllocatableEnforcement,
				VolumePluginDir:                           DefaultVolumePluginDir,
				Logging: logsapi.LoggingConfiguration{
					Format:         "text",
					FlushFrequency: logsapi.TimeOrMetaDuration{Duration: metav1.Duration{Duration: 5 * time.Second}, SerializeAsString: true},
				},
				EnableSystemLogHandler:        ptr.To(true),
				EnableProfilingHandler:        ptr.To(true),
				EnableDebugFlagsHandler:       ptr.To(true),
				SeccompDefault:                ptr.To(false),
				FailCgroupV1:                  ptr.To(true),
				MemoryThrottlingFactor:        ptr.To(DefaultMemoryThrottlingFactor),
				MemoryReservationPolicy:       v1beta1.NoneMemoryReservationPolicy,
				RegisterNode:                  ptr.To(true),
				LocalStorageCapacityIsolation: ptr.To(true),
				PodLogsDir:                    DefaultPodLogsDir,
				SingleProcessOOMKill:          nil,
				CrashLoopBackOff:              v1beta1.CrashLoopBackOffConfig{},
			},
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			SetDefaults_KubeletConfiguration(tc.config)
			if diff := cmp.Diff(tc.expected, tc.config); diff != "" {
				t.Errorf("Got unexpected defaults (-want, +got):\n%s", diff)
			}
		})
	}
}
