kubernetes scheme_test 源码
kubernetes scheme_test 代码
文件路径:/pkg/scheduler/apis/config/scheme/scheme_test.go
/*
Copyright 2020 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 scheme
import (
"bytes"
"testing"
"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
v1 "k8s.io/kube-scheduler/config/v1"
"k8s.io/kube-scheduler/config/v1beta2"
"k8s.io/kube-scheduler/config/v1beta3"
"k8s.io/kubernetes/pkg/scheduler/apis/config"
"k8s.io/kubernetes/pkg/scheduler/apis/config/testing/defaults"
"k8s.io/utils/pointer"
"sigs.k8s.io/yaml"
)
// TestCodecsDecodePluginConfig tests that embedded plugin args get decoded
// into their appropriate internal types and defaults are applied.
func TestCodecsDecodePluginConfig(t *testing.T) {
testCases := []struct {
name string
data []byte
wantErr string
wantProfiles []config.KubeSchedulerProfile
}{
// v1beta2 tests
{
name: "v1beta2 all plugin args in default profile",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
minCandidateNodesPercentage: 50
minCandidateNodesAbsolute: 500
- name: InterPodAffinity
args:
hardPodAffinityWeight: 5
- name: NodeResourcesFit
args:
ignoredResources: ["foo"]
- name: PodTopologySpread
args:
defaultConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: ScheduleAnyway
- name: VolumeBinding
args:
bindTimeoutSeconds: 300
- name: NodeAffinity
args:
addedAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: foo
operator: In
values: ["bar"]
- name: NodeResourcesBalancedAllocation
args:
resources:
- name: cpu # default weight(1) will be set.
- name: memory # weight 0 will be replaced by 1.
weight: 0
- name: scalar0
weight: 1
- name: scalar1 # default weight(1) will be set for scalar1
- name: scalar2 # weight 0 will be replaced by 1.
weight: 0
- name: scalar3
weight: 2
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1beta2,
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 500},
},
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{HardPodAffinityWeight: 5},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
IgnoredResources: []string{"foo"},
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
},
},
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{
DefaultConstraints: []corev1.TopologySpreadConstraint{
{MaxSkew: 1, TopologyKey: "zone", WhenUnsatisfiable: corev1.ScheduleAnyway},
},
DefaultingType: config.SystemDefaulting,
},
},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 300,
},
},
{
Name: "NodeAffinity",
Args: &config.NodeAffinityArgs{
AddedAffinity: &corev1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
NodeSelectorTerms: []corev1.NodeSelectorTerm{
{
MatchExpressions: []corev1.NodeSelectorRequirement{
{
Key: "foo",
Operator: corev1.NodeSelectorOpIn,
Values: []string{"bar"},
},
},
},
},
},
},
},
},
{
Name: "NodeResourcesBalancedAllocation",
Args: &config.NodeResourcesBalancedAllocationArgs{
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
{Name: "scalar0", Weight: 1},
{Name: "scalar1", Weight: 1},
{Name: "scalar2", Weight: 1},
{Name: "scalar3", Weight: 2}},
},
},
},
},
},
},
{
name: "v1beta2 plugins can include version and kind",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: DefaultPreemptionArgs
minCandidateNodesPercentage: 50
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1beta2,
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 100},
},
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{
HardPodAffinityWeight: 1,
},
},
{
Name: "NodeAffinity",
Args: &config.NodeAffinityArgs{},
},
{
Name: "NodeResourcesBalancedAllocation",
Args: &config.NodeResourcesBalancedAllocationArgs{
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
},
},
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{
DefaultingType: config.SystemDefaulting,
},
},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 600,
},
},
},
},
},
},
{
name: "plugin group and kind should match the type",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: InterPodAffinityArgs
`),
wantErr: `decoding .profiles[0].pluginConfig[0]: args for plugin DefaultPreemption were not of type DefaultPreemptionArgs.kubescheduler.config.k8s.io, got InterPodAffinityArgs.kubescheduler.config.k8s.io`,
},
{
name: "v1beta2 NodResourcesFitArgs shape encoding is strict",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: NodeResourcesFit
args:
scoringStrategy:
requestedToCapacityRatio:
shape:
- Score: 2
Utilization: 1
`),
wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Score", unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Utilization"`,
},
{
name: "v1beta2 NodeResourcesFitArgs resources encoding is strict",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: NodeResourcesFit
args:
scoringStrategy:
resources:
- Name: cpu
Weight: 1
`),
wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.resources[0].Name", unknown field "scoringStrategy.resources[0].Weight"`,
},
{
name: "out-of-tree plugin args",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: OutOfTreePlugin
args:
foo: bar
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1beta2,
PluginConfig: append([]config.PluginConfig{
{
Name: "OutOfTreePlugin",
Args: &runtime.Unknown{
ContentType: "application/json",
Raw: []byte(`{"foo":"bar"}`),
},
},
}, defaults.PluginConfigsV1beta2...),
},
},
},
{
name: "empty and no plugin args",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
- name: InterPodAffinity
args:
- name: NodeResourcesFit
- name: OutOfTreePlugin
args:
- name: VolumeBinding
args:
- name: PodTopologySpread
- name: NodeAffinity
- name: NodeResourcesBalancedAllocation
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1beta2,
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
},
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{
HardPodAffinityWeight: 1,
},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
},
},
},
},
{Name: "OutOfTreePlugin"},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 600,
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{
DefaultingType: config.SystemDefaulting,
},
},
{
Name: "NodeAffinity",
Args: &config.NodeAffinityArgs{},
},
{
Name: "NodeResourcesBalancedAllocation",
Args: &config.NodeResourcesBalancedAllocationArgs{
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
},
},
},
},
},
},
// v1beta3 tests
{
name: "v1beta3 all plugin args in default profile",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
minCandidateNodesPercentage: 50
minCandidateNodesAbsolute: 500
- name: InterPodAffinity
args:
hardPodAffinityWeight: 5
- name: NodeResourcesFit
args:
ignoredResources: ["foo"]
- name: PodTopologySpread
args:
defaultConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: ScheduleAnyway
- name: VolumeBinding
args:
bindTimeoutSeconds: 300
- name: NodeAffinity
args:
addedAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: foo
operator: In
values: ["bar"]
- name: NodeResourcesBalancedAllocation
args:
resources:
- name: cpu # default weight(1) will be set.
- name: memory # weight 0 will be replaced by 1.
weight: 0
- name: scalar0
weight: 1
- name: scalar1 # default weight(1) will be set for scalar1
- name: scalar2 # weight 0 will be replaced by 1.
weight: 0
- name: scalar3
weight: 2
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1beta3,
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 500},
},
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{HardPodAffinityWeight: 5},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
IgnoredResources: []string{"foo"},
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
},
},
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{
DefaultConstraints: []corev1.TopologySpreadConstraint{
{MaxSkew: 1, TopologyKey: "zone", WhenUnsatisfiable: corev1.ScheduleAnyway},
},
DefaultingType: config.SystemDefaulting,
},
},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 300,
},
},
{
Name: "NodeAffinity",
Args: &config.NodeAffinityArgs{
AddedAffinity: &corev1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
NodeSelectorTerms: []corev1.NodeSelectorTerm{
{
MatchExpressions: []corev1.NodeSelectorRequirement{
{
Key: "foo",
Operator: corev1.NodeSelectorOpIn,
Values: []string{"bar"},
},
},
},
},
},
},
},
},
{
Name: "NodeResourcesBalancedAllocation",
Args: &config.NodeResourcesBalancedAllocationArgs{
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
{Name: "scalar0", Weight: 1},
{Name: "scalar1", Weight: 1},
{Name: "scalar2", Weight: 1},
{Name: "scalar3", Weight: 2}},
},
},
},
},
},
},
{
name: "v1beta3 plugins can include version and kind",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: DefaultPreemptionArgs
minCandidateNodesPercentage: 50
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1beta3,
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 100},
},
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{
HardPodAffinityWeight: 1,
},
},
{
Name: "NodeAffinity",
Args: &config.NodeAffinityArgs{},
},
{
Name: "NodeResourcesBalancedAllocation",
Args: &config.NodeResourcesBalancedAllocationArgs{
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
},
},
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{
DefaultingType: config.SystemDefaulting,
},
},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 600,
},
},
},
},
},
},
{
name: "plugin group and kind should match the type",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: InterPodAffinityArgs
`),
wantErr: `decoding .profiles[0].pluginConfig[0]: args for plugin DefaultPreemption were not of type DefaultPreemptionArgs.kubescheduler.config.k8s.io, got InterPodAffinityArgs.kubescheduler.config.k8s.io`,
},
{
name: "v1beta3 NodResourcesFitArgs shape encoding is strict",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: NodeResourcesFit
args:
scoringStrategy:
requestedToCapacityRatio:
shape:
- Score: 2
Utilization: 1
`),
wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Score", unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Utilization"`,
},
{
name: "v1beta3 NodeResourcesFitArgs resources encoding is strict",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: NodeResourcesFit
args:
scoringStrategy:
resources:
- Name: cpu
Weight: 1
`),
wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.resources[0].Name", unknown field "scoringStrategy.resources[0].Weight"`,
},
{
name: "out-of-tree plugin args",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: OutOfTreePlugin
args:
foo: bar
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1beta3,
PluginConfig: append([]config.PluginConfig{
{
Name: "OutOfTreePlugin",
Args: &runtime.Unknown{
ContentType: "application/json",
Raw: []byte(`{"foo":"bar"}`),
},
},
}, defaults.PluginConfigsV1beta3...),
},
},
},
{
name: "empty and no plugin args",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
- name: InterPodAffinity
args:
- name: NodeResourcesFit
- name: OutOfTreePlugin
args:
- name: VolumeBinding
args:
- name: PodTopologySpread
- name: NodeAffinity
- name: NodeResourcesBalancedAllocation
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1beta3,
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
},
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{
HardPodAffinityWeight: 1,
},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
},
},
},
},
{Name: "OutOfTreePlugin"},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 600,
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{
DefaultingType: config.SystemDefaulting,
},
},
{
Name: "NodeAffinity",
Args: &config.NodeAffinityArgs{},
},
{
Name: "NodeResourcesBalancedAllocation",
Args: &config.NodeResourcesBalancedAllocationArgs{
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
},
},
},
},
},
},
// v1 tests
{
name: "v1 all plugin args in default profile",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
minCandidateNodesPercentage: 50
minCandidateNodesAbsolute: 500
- name: InterPodAffinity
args:
hardPodAffinityWeight: 5
- name: NodeResourcesFit
args:
ignoredResources: ["foo"]
- name: PodTopologySpread
args:
defaultConstraints:
- maxSkew: 1
topologyKey: zone
whenUnsatisfiable: ScheduleAnyway
- name: VolumeBinding
args:
bindTimeoutSeconds: 300
- name: NodeAffinity
args:
addedAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: foo
operator: In
values: ["bar"]
- name: NodeResourcesBalancedAllocation
args:
resources:
- name: cpu # default weight(1) will be set.
- name: memory # weight 0 will be replaced by 1.
weight: 0
- name: scalar0
weight: 1
- name: scalar1 # default weight(1) will be set for scalar1
- name: scalar2 # weight 0 will be replaced by 1.
weight: 0
- name: scalar3
weight: 2
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1,
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 500},
},
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{HardPodAffinityWeight: 5},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
IgnoredResources: []string{"foo"},
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
},
},
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{
DefaultConstraints: []corev1.TopologySpreadConstraint{
{MaxSkew: 1, TopologyKey: "zone", WhenUnsatisfiable: corev1.ScheduleAnyway},
},
DefaultingType: config.SystemDefaulting,
},
},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 300,
},
},
{
Name: "NodeAffinity",
Args: &config.NodeAffinityArgs{
AddedAffinity: &corev1.NodeAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: &corev1.NodeSelector{
NodeSelectorTerms: []corev1.NodeSelectorTerm{
{
MatchExpressions: []corev1.NodeSelectorRequirement{
{
Key: "foo",
Operator: corev1.NodeSelectorOpIn,
Values: []string{"bar"},
},
},
},
},
},
},
},
},
{
Name: "NodeResourcesBalancedAllocation",
Args: &config.NodeResourcesBalancedAllocationArgs{
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
{Name: "scalar0", Weight: 1},
{Name: "scalar1", Weight: 1},
{Name: "scalar2", Weight: 1},
{Name: "scalar3", Weight: 2}},
},
},
},
},
},
},
{
name: "v1 plugins can include version and kind",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
apiVersion: kubescheduler.config.k8s.io/v1
kind: DefaultPreemptionArgs
minCandidateNodesPercentage: 50
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1,
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 50, MinCandidateNodesAbsolute: 100},
},
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{
HardPodAffinityWeight: 1,
},
},
{
Name: "NodeAffinity",
Args: &config.NodeAffinityArgs{},
},
{
Name: "NodeResourcesBalancedAllocation",
Args: &config.NodeResourcesBalancedAllocationArgs{
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
},
},
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{
DefaultingType: config.SystemDefaulting,
},
},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 600,
},
},
},
},
},
},
{
name: "plugin group and kind should match the type",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
apiVersion: kubescheduler.config.k8s.io/v1
kind: InterPodAffinityArgs
`),
wantErr: `decoding .profiles[0].pluginConfig[0]: args for plugin DefaultPreemption were not of type DefaultPreemptionArgs.kubescheduler.config.k8s.io, got InterPodAffinityArgs.kubescheduler.config.k8s.io`,
},
{
name: "v1 NodResourcesFitArgs shape encoding is strict",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: NodeResourcesFit
args:
scoringStrategy:
requestedToCapacityRatio:
shape:
- Score: 2
Utilization: 1
`),
wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Score", unknown field "scoringStrategy.requestedToCapacityRatio.shape[0].Utilization"`,
},
{
name: "v1 NodeResourcesFitArgs resources encoding is strict",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: NodeResourcesFit
args:
scoringStrategy:
resources:
- Name: cpu
Weight: 1
`),
wantErr: `strict decoding error: decoding .profiles[0].pluginConfig[0]: strict decoding error: decoding args for plugin NodeResourcesFit: strict decoding error: unknown field "scoringStrategy.resources[0].Name", unknown field "scoringStrategy.resources[0].Weight"`,
},
{
name: "out-of-tree plugin args",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: OutOfTreePlugin
args:
foo: bar
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1,
PluginConfig: append([]config.PluginConfig{
{
Name: "OutOfTreePlugin",
Args: &runtime.Unknown{
ContentType: "application/json",
Raw: []byte(`{"foo":"bar"}`),
},
},
}, defaults.PluginConfigsV1...),
},
},
},
{
name: "empty and no plugin args",
data: []byte(`
apiVersion: kubescheduler.config.k8s.io/v1
kind: KubeSchedulerConfiguration
profiles:
- pluginConfig:
- name: DefaultPreemption
args:
- name: InterPodAffinity
args:
- name: NodeResourcesFit
- name: OutOfTreePlugin
args:
- name: VolumeBinding
args:
- name: PodTopologySpread
- name: NodeAffinity
- name: NodeResourcesBalancedAllocation
`),
wantProfiles: []config.KubeSchedulerProfile{
{
SchedulerName: "default-scheduler",
Plugins: defaults.PluginsV1,
PluginConfig: []config.PluginConfig{
{
Name: "DefaultPreemption",
Args: &config.DefaultPreemptionArgs{MinCandidateNodesPercentage: 10, MinCandidateNodesAbsolute: 100},
},
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{
HardPodAffinityWeight: 1,
},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{
{Name: "cpu", Weight: 1},
{Name: "memory", Weight: 1},
},
},
},
},
{Name: "OutOfTreePlugin"},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 600,
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{
DefaultingType: config.SystemDefaulting,
},
},
{
Name: "NodeAffinity",
Args: &config.NodeAffinityArgs{},
},
{
Name: "NodeResourcesBalancedAllocation",
Args: &config.NodeResourcesBalancedAllocationArgs{
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}, {Name: "memory", Weight: 1}},
},
},
},
},
},
},
}
decoder := Codecs.UniversalDecoder()
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
obj, gvk, err := decoder.Decode(tt.data, nil, nil)
if err != nil {
if tt.wantErr != err.Error() {
t.Fatalf("\ngot err:\n\t%v\nwant:\n\t%s", err, tt.wantErr)
}
return
}
if len(tt.wantErr) != 0 {
t.Fatalf("no error produced, wanted %v", tt.wantErr)
}
got, ok := obj.(*config.KubeSchedulerConfiguration)
if !ok {
t.Fatalf("decoded into %s, want %s", gvk, config.SchemeGroupVersion.WithKind("KubeSchedulerConfiguration"))
}
if diff := cmp.Diff(tt.wantProfiles, got.Profiles); diff != "" {
t.Errorf("unexpected configuration (-want,+got):\n%s", diff)
}
})
}
}
func TestCodecsEncodePluginConfig(t *testing.T) {
testCases := []struct {
name string
obj runtime.Object
version schema.GroupVersion
want string
}{
//v1beta2 tests
{
name: "v1beta2 in-tree and out-of-tree plugins",
version: v1beta2.SchemeGroupVersion,
obj: &v1beta2.KubeSchedulerConfiguration{
Profiles: []v1beta2.KubeSchedulerProfile{
{
PluginConfig: []v1beta2.PluginConfig{
{
Name: "InterPodAffinity",
Args: runtime.RawExtension{
Object: &v1beta2.InterPodAffinityArgs{
HardPodAffinityWeight: pointer.Int32(5),
},
},
},
{
Name: "VolumeBinding",
Args: runtime.RawExtension{
Object: &v1beta2.VolumeBindingArgs{
BindTimeoutSeconds: pointer.Int64(300),
Shape: []v1beta2.UtilizationShapePoint{
{
Utilization: 0,
Score: 0,
},
{
Utilization: 100,
Score: 10,
},
},
},
},
},
{
Name: "NodeResourcesFit",
Args: runtime.RawExtension{
Object: &v1beta2.NodeResourcesFitArgs{
ScoringStrategy: &v1beta2.ScoringStrategy{
Type: v1beta2.RequestedToCapacityRatio,
Resources: []v1beta2.ResourceSpec{{Name: "cpu", Weight: 1}},
RequestedToCapacityRatio: &v1beta2.RequestedToCapacityRatioParam{
Shape: []v1beta2.UtilizationShapePoint{
{Utilization: 1, Score: 2},
},
},
},
},
},
},
{
Name: "PodTopologySpread",
Args: runtime.RawExtension{
Object: &v1beta2.PodTopologySpreadArgs{
DefaultConstraints: []corev1.TopologySpreadConstraint{},
},
},
},
{
Name: "OutOfTreePlugin",
Args: runtime.RawExtension{
Raw: []byte(`{"foo":"bar"}`),
},
},
},
},
},
},
want: `apiVersion: kubescheduler.config.k8s.io/v1beta2
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: ""
qps: 0
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: null
leaseDuration: 0s
renewDeadline: 0s
resourceLock: ""
resourceName: ""
resourceNamespace: ""
retryPeriod: 0s
profiles:
- pluginConfig:
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
hardPodAffinityWeight: 5
kind: InterPodAffinityArgs
name: InterPodAffinity
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
bindTimeoutSeconds: 300
kind: VolumeBindingArgs
shape:
- score: 0
utilization: 0
- score: 10
utilization: 100
name: VolumeBinding
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: NodeResourcesFitArgs
scoringStrategy:
requestedToCapacityRatio:
shape:
- score: 2
utilization: 1
resources:
- name: cpu
weight: 1
type: RequestedToCapacityRatio
name: NodeResourcesFit
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: PodTopologySpreadArgs
name: PodTopologySpread
- args:
foo: bar
name: OutOfTreePlugin
`,
},
{
name: "v1beta2 in-tree and out-of-tree plugins from internal",
version: v1beta2.SchemeGroupVersion,
obj: &config.KubeSchedulerConfiguration{
Parallelism: 8,
Profiles: []config.KubeSchedulerProfile{
{
PluginConfig: []config.PluginConfig{
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{
HardPodAffinityWeight: 5,
},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}},
},
},
},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 300,
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{},
},
{
Name: "OutOfTreePlugin",
Args: &runtime.Unknown{
Raw: []byte(`{"foo":"bar"}`),
},
},
},
},
},
},
want: `apiVersion: kubescheduler.config.k8s.io/v1beta2
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: ""
qps: 0
enableContentionProfiling: false
enableProfiling: false
healthzBindAddress: ""
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: false
leaseDuration: 0s
renewDeadline: 0s
resourceLock: ""
resourceName: ""
resourceNamespace: ""
retryPeriod: 0s
metricsBindAddress: ""
parallelism: 8
percentageOfNodesToScore: 0
podInitialBackoffSeconds: 0
podMaxBackoffSeconds: 0
profiles:
- pluginConfig:
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
hardPodAffinityWeight: 5
kind: InterPodAffinityArgs
name: InterPodAffinity
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: NodeResourcesFitArgs
scoringStrategy:
resources:
- name: cpu
weight: 1
type: LeastAllocated
name: NodeResourcesFit
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
bindTimeoutSeconds: 300
kind: VolumeBindingArgs
name: VolumeBinding
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta2
kind: PodTopologySpreadArgs
name: PodTopologySpread
- args:
foo: bar
name: OutOfTreePlugin
schedulerName: ""
`,
},
//v1beta3 tests
{
name: "v1beta3 in-tree and out-of-tree plugins",
version: v1beta3.SchemeGroupVersion,
obj: &v1beta3.KubeSchedulerConfiguration{
Profiles: []v1beta3.KubeSchedulerProfile{
{
PluginConfig: []v1beta3.PluginConfig{
{
Name: "InterPodAffinity",
Args: runtime.RawExtension{
Object: &v1beta3.InterPodAffinityArgs{
HardPodAffinityWeight: pointer.Int32(5),
},
},
},
{
Name: "VolumeBinding",
Args: runtime.RawExtension{
Object: &v1beta2.VolumeBindingArgs{
BindTimeoutSeconds: pointer.Int64(300),
Shape: []v1beta2.UtilizationShapePoint{
{
Utilization: 0,
Score: 0,
},
{
Utilization: 100,
Score: 10,
},
},
},
},
},
{
Name: "NodeResourcesFit",
Args: runtime.RawExtension{
Object: &v1beta3.NodeResourcesFitArgs{
ScoringStrategy: &v1beta3.ScoringStrategy{
Type: v1beta3.RequestedToCapacityRatio,
Resources: []v1beta3.ResourceSpec{{Name: "cpu", Weight: 1}},
RequestedToCapacityRatio: &v1beta3.RequestedToCapacityRatioParam{
Shape: []v1beta3.UtilizationShapePoint{
{Utilization: 1, Score: 2},
},
},
},
},
},
},
{
Name: "PodTopologySpread",
Args: runtime.RawExtension{
Object: &v1beta3.PodTopologySpreadArgs{
DefaultConstraints: []corev1.TopologySpreadConstraint{},
},
},
},
{
Name: "OutOfTreePlugin",
Args: runtime.RawExtension{
Raw: []byte(`{"foo":"bar"}`),
},
},
},
},
},
},
want: `apiVersion: kubescheduler.config.k8s.io/v1beta3
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: ""
qps: 0
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: null
leaseDuration: 0s
renewDeadline: 0s
resourceLock: ""
resourceName: ""
resourceNamespace: ""
retryPeriod: 0s
profiles:
- pluginConfig:
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
hardPodAffinityWeight: 5
kind: InterPodAffinityArgs
name: InterPodAffinity
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
bindTimeoutSeconds: 300
kind: VolumeBindingArgs
shape:
- score: 0
utilization: 0
- score: 10
utilization: 100
name: VolumeBinding
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: NodeResourcesFitArgs
scoringStrategy:
requestedToCapacityRatio:
shape:
- score: 2
utilization: 1
resources:
- name: cpu
weight: 1
type: RequestedToCapacityRatio
name: NodeResourcesFit
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: PodTopologySpreadArgs
name: PodTopologySpread
- args:
foo: bar
name: OutOfTreePlugin
`,
},
{
name: "v1beta3 in-tree and out-of-tree plugins from internal",
version: v1beta3.SchemeGroupVersion,
obj: &config.KubeSchedulerConfiguration{
Parallelism: 8,
Profiles: []config.KubeSchedulerProfile{
{
PluginConfig: []config.PluginConfig{
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{
HardPodAffinityWeight: 5,
},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}},
},
},
},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 300,
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{},
},
{
Name: "OutOfTreePlugin",
Args: &runtime.Unknown{
Raw: []byte(`{"foo":"bar"}`),
},
},
},
},
},
},
want: `apiVersion: kubescheduler.config.k8s.io/v1beta3
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: ""
qps: 0
enableContentionProfiling: false
enableProfiling: false
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: false
leaseDuration: 0s
renewDeadline: 0s
resourceLock: ""
resourceName: ""
resourceNamespace: ""
retryPeriod: 0s
parallelism: 8
percentageOfNodesToScore: 0
podInitialBackoffSeconds: 0
podMaxBackoffSeconds: 0
profiles:
- pluginConfig:
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
hardPodAffinityWeight: 5
kind: InterPodAffinityArgs
name: InterPodAffinity
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: NodeResourcesFitArgs
scoringStrategy:
resources:
- name: cpu
weight: 1
type: LeastAllocated
name: NodeResourcesFit
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
bindTimeoutSeconds: 300
kind: VolumeBindingArgs
name: VolumeBinding
- args:
apiVersion: kubescheduler.config.k8s.io/v1beta3
kind: PodTopologySpreadArgs
name: PodTopologySpread
- args:
foo: bar
name: OutOfTreePlugin
schedulerName: ""
`,
},
//v1 tests
{
name: "v1 in-tree and out-of-tree plugins",
version: v1.SchemeGroupVersion,
obj: &v1.KubeSchedulerConfiguration{
Profiles: []v1.KubeSchedulerProfile{
{
PluginConfig: []v1.PluginConfig{
{
Name: "InterPodAffinity",
Args: runtime.RawExtension{
Object: &v1.InterPodAffinityArgs{
HardPodAffinityWeight: pointer.Int32(5),
},
},
},
{
Name: "VolumeBinding",
Args: runtime.RawExtension{
Object: &v1.VolumeBindingArgs{
BindTimeoutSeconds: pointer.Int64(300),
Shape: []v1.UtilizationShapePoint{
{
Utilization: 0,
Score: 0,
},
{
Utilization: 100,
Score: 10,
},
},
},
},
},
{
Name: "NodeResourcesFit",
Args: runtime.RawExtension{
Object: &v1.NodeResourcesFitArgs{
ScoringStrategy: &v1.ScoringStrategy{
Type: v1.RequestedToCapacityRatio,
Resources: []v1.ResourceSpec{{Name: "cpu", Weight: 1}},
RequestedToCapacityRatio: &v1.RequestedToCapacityRatioParam{
Shape: []v1.UtilizationShapePoint{
{Utilization: 1, Score: 2},
},
},
},
},
},
},
{
Name: "PodTopologySpread",
Args: runtime.RawExtension{
Object: &v1.PodTopologySpreadArgs{
DefaultConstraints: []corev1.TopologySpreadConstraint{},
},
},
},
{
Name: "OutOfTreePlugin",
Args: runtime.RawExtension{
Raw: []byte(`{"foo":"bar"}`),
},
},
},
},
},
},
want: `apiVersion: kubescheduler.config.k8s.io/v1
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: ""
qps: 0
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: null
leaseDuration: 0s
renewDeadline: 0s
resourceLock: ""
resourceName: ""
resourceNamespace: ""
retryPeriod: 0s
profiles:
- pluginConfig:
- args:
apiVersion: kubescheduler.config.k8s.io/v1
hardPodAffinityWeight: 5
kind: InterPodAffinityArgs
name: InterPodAffinity
- args:
apiVersion: kubescheduler.config.k8s.io/v1
bindTimeoutSeconds: 300
kind: VolumeBindingArgs
shape:
- score: 0
utilization: 0
- score: 10
utilization: 100
name: VolumeBinding
- args:
apiVersion: kubescheduler.config.k8s.io/v1
kind: NodeResourcesFitArgs
scoringStrategy:
requestedToCapacityRatio:
shape:
- score: 2
utilization: 1
resources:
- name: cpu
weight: 1
type: RequestedToCapacityRatio
name: NodeResourcesFit
- args:
apiVersion: kubescheduler.config.k8s.io/v1
kind: PodTopologySpreadArgs
name: PodTopologySpread
- args:
foo: bar
name: OutOfTreePlugin
`,
},
{
name: "v1 in-tree and out-of-tree plugins from internal",
version: v1.SchemeGroupVersion,
obj: &config.KubeSchedulerConfiguration{
Parallelism: 8,
Profiles: []config.KubeSchedulerProfile{
{
PluginConfig: []config.PluginConfig{
{
Name: "InterPodAffinity",
Args: &config.InterPodAffinityArgs{
HardPodAffinityWeight: 5,
},
},
{
Name: "NodeResourcesFit",
Args: &config.NodeResourcesFitArgs{
ScoringStrategy: &config.ScoringStrategy{
Type: config.LeastAllocated,
Resources: []config.ResourceSpec{{Name: "cpu", Weight: 1}},
},
},
},
{
Name: "VolumeBinding",
Args: &config.VolumeBindingArgs{
BindTimeoutSeconds: 300,
},
},
{
Name: "PodTopologySpread",
Args: &config.PodTopologySpreadArgs{},
},
{
Name: "OutOfTreePlugin",
Args: &runtime.Unknown{
Raw: []byte(`{"foo":"bar"}`),
},
},
},
},
},
},
want: `apiVersion: kubescheduler.config.k8s.io/v1
clientConnection:
acceptContentTypes: ""
burst: 0
contentType: ""
kubeconfig: ""
qps: 0
enableContentionProfiling: false
enableProfiling: false
kind: KubeSchedulerConfiguration
leaderElection:
leaderElect: false
leaseDuration: 0s
renewDeadline: 0s
resourceLock: ""
resourceName: ""
resourceNamespace: ""
retryPeriod: 0s
parallelism: 8
percentageOfNodesToScore: 0
podInitialBackoffSeconds: 0
podMaxBackoffSeconds: 0
profiles:
- pluginConfig:
- args:
apiVersion: kubescheduler.config.k8s.io/v1
hardPodAffinityWeight: 5
kind: InterPodAffinityArgs
name: InterPodAffinity
- args:
apiVersion: kubescheduler.config.k8s.io/v1
kind: NodeResourcesFitArgs
scoringStrategy:
resources:
- name: cpu
weight: 1
type: LeastAllocated
name: NodeResourcesFit
- args:
apiVersion: kubescheduler.config.k8s.io/v1
bindTimeoutSeconds: 300
kind: VolumeBindingArgs
name: VolumeBinding
- args:
apiVersion: kubescheduler.config.k8s.io/v1
kind: PodTopologySpreadArgs
name: PodTopologySpread
- args:
foo: bar
name: OutOfTreePlugin
schedulerName: ""
`,
},
}
yamlInfo, ok := runtime.SerializerInfoForMediaType(Codecs.SupportedMediaTypes(), runtime.ContentTypeYAML)
if !ok {
t.Fatalf("unable to locate encoder -- %q is not a supported media type", runtime.ContentTypeYAML)
}
jsonInfo, ok := runtime.SerializerInfoForMediaType(Codecs.SupportedMediaTypes(), runtime.ContentTypeJSON)
if !ok {
t.Fatalf("unable to locate encoder -- %q is not a supported media type", runtime.ContentTypeJSON)
}
for _, tt := range testCases {
t.Run(tt.name, func(t *testing.T) {
encoder := Codecs.EncoderForVersion(yamlInfo.Serializer, tt.version)
var buf bytes.Buffer
if err := encoder.Encode(tt.obj, &buf); err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, buf.String()); diff != "" {
t.Errorf("unexpected encoded configuration:\n%s", diff)
}
encoder = Codecs.EncoderForVersion(jsonInfo.Serializer, tt.version)
buf = bytes.Buffer{}
if err := encoder.Encode(tt.obj, &buf); err != nil {
t.Fatal(err)
}
out, err := yaml.JSONToYAML(buf.Bytes())
if err != nil {
t.Fatal(err)
}
if diff := cmp.Diff(tt.want, string(out)); diff != "" {
t.Errorf("unexpected encoded configuration:\n%s", diff)
}
})
}
}
相关信息
相关文章
0
赞
热门推荐
-
2、 - 优质文章
-
3、 gate.io
-
8、 golang
-
9、 openharmony
-
10、 Vue中input框自动聚焦