...

Source file src/k8s.io/kubernetes/pkg/scheduler/profile/profile_test.go

Documentation: k8s.io/kubernetes/pkg/scheduler/profile

     1  /*
     2  Copyright 2020 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package profile
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"strings"
    23  	"testing"
    24  
    25  	v1 "k8s.io/api/core/v1"
    26  	"k8s.io/apimachinery/pkg/runtime"
    27  	"k8s.io/client-go/tools/events"
    28  	"k8s.io/klog/v2/ktesting"
    29  	"k8s.io/kubernetes/pkg/scheduler/apis/config"
    30  	"k8s.io/kubernetes/pkg/scheduler/framework"
    31  	frameworkruntime "k8s.io/kubernetes/pkg/scheduler/framework/runtime"
    32  )
    33  
    34  var fakeRegistry = frameworkruntime.Registry{
    35  	"QueueSort": newFakePlugin("QueueSort"),
    36  	"Bind1":     newFakePlugin("Bind1"),
    37  	"Bind2":     newFakePlugin("Bind2"),
    38  	"Another":   newFakePlugin("Another"),
    39  }
    40  
    41  func TestNewMap(t *testing.T) {
    42  	cases := []struct {
    43  		name    string
    44  		cfgs    []config.KubeSchedulerProfile
    45  		wantErr string
    46  	}{
    47  		{
    48  			name: "valid",
    49  			cfgs: []config.KubeSchedulerProfile{
    50  				{
    51  					SchedulerName: "profile-1",
    52  					Plugins: &config.Plugins{
    53  						QueueSort: config.PluginSet{
    54  							Enabled: []config.Plugin{
    55  								{Name: "QueueSort"},
    56  							},
    57  						},
    58  						Bind: config.PluginSet{
    59  							Enabled: []config.Plugin{
    60  								{Name: "Bind1"},
    61  							},
    62  						},
    63  					},
    64  				},
    65  				{
    66  					SchedulerName: "profile-2",
    67  					Plugins: &config.Plugins{
    68  						QueueSort: config.PluginSet{
    69  							Enabled: []config.Plugin{
    70  								{Name: "QueueSort"},
    71  							},
    72  						},
    73  						Bind: config.PluginSet{
    74  							Enabled: []config.Plugin{
    75  								{Name: "Bind2"},
    76  							},
    77  						},
    78  					},
    79  					PluginConfig: []config.PluginConfig{
    80  						{
    81  							Name: "Bind2",
    82  							Args: &runtime.Unknown{Raw: []byte("{}")},
    83  						},
    84  					},
    85  				},
    86  			},
    87  		},
    88  		{
    89  			name: "different queue sort",
    90  			cfgs: []config.KubeSchedulerProfile{
    91  				{
    92  					SchedulerName: "profile-1",
    93  					Plugins: &config.Plugins{
    94  						QueueSort: config.PluginSet{
    95  							Enabled: []config.Plugin{
    96  								{Name: "QueueSort"},
    97  							},
    98  						},
    99  						Bind: config.PluginSet{
   100  							Enabled: []config.Plugin{
   101  								{Name: "Bind1"},
   102  							},
   103  						},
   104  					},
   105  				},
   106  				{
   107  					SchedulerName: "profile-2",
   108  					Plugins: &config.Plugins{
   109  						QueueSort: config.PluginSet{
   110  							Enabled: []config.Plugin{
   111  								{Name: "Another"},
   112  							},
   113  						},
   114  						Bind: config.PluginSet{
   115  							Enabled: []config.Plugin{
   116  								{Name: "Bind2"},
   117  							},
   118  						},
   119  					},
   120  				},
   121  			},
   122  			wantErr: "different queue sort plugins",
   123  		},
   124  		{
   125  			name: "different queue sort args",
   126  			cfgs: []config.KubeSchedulerProfile{
   127  				{
   128  					SchedulerName: "profile-1",
   129  					Plugins: &config.Plugins{
   130  						QueueSort: config.PluginSet{
   131  							Enabled: []config.Plugin{
   132  								{Name: "QueueSort"},
   133  							},
   134  						},
   135  						Bind: config.PluginSet{
   136  							Enabled: []config.Plugin{
   137  								{Name: "Bind1"},
   138  							},
   139  						},
   140  					},
   141  					PluginConfig: []config.PluginConfig{
   142  						{
   143  							Name: "QueueSort",
   144  							Args: &runtime.Unknown{Raw: []byte("{}")},
   145  						},
   146  					},
   147  				},
   148  				{
   149  					SchedulerName: "profile-2",
   150  					Plugins: &config.Plugins{
   151  						QueueSort: config.PluginSet{
   152  							Enabled: []config.Plugin{
   153  								{Name: "QueueSort"},
   154  							},
   155  						},
   156  						Bind: config.PluginSet{
   157  							Enabled: []config.Plugin{
   158  								{Name: "Bind2"},
   159  							},
   160  						},
   161  					},
   162  				},
   163  			},
   164  			wantErr: "different queue sort plugin args",
   165  		},
   166  		{
   167  			name: "duplicate scheduler name",
   168  			cfgs: []config.KubeSchedulerProfile{
   169  				{
   170  					SchedulerName: "profile-1",
   171  					Plugins: &config.Plugins{
   172  						QueueSort: config.PluginSet{
   173  							Enabled: []config.Plugin{
   174  								{Name: "QueueSort"},
   175  							},
   176  						},
   177  						Bind: config.PluginSet{
   178  							Enabled: []config.Plugin{
   179  								{Name: "Bind1"},
   180  							},
   181  						},
   182  					},
   183  				},
   184  				{
   185  					SchedulerName: "profile-1",
   186  					Plugins: &config.Plugins{
   187  						QueueSort: config.PluginSet{
   188  							Enabled: []config.Plugin{
   189  								{Name: "QueueSort"},
   190  							},
   191  						},
   192  						Bind: config.PluginSet{
   193  							Enabled: []config.Plugin{
   194  								{Name: "Bind2"},
   195  							},
   196  						},
   197  					},
   198  				},
   199  			},
   200  			wantErr: "duplicate profile",
   201  		},
   202  		{
   203  			name: "scheduler name is needed",
   204  			cfgs: []config.KubeSchedulerProfile{
   205  				{
   206  					Plugins: &config.Plugins{
   207  						QueueSort: config.PluginSet{
   208  							Enabled: []config.Plugin{
   209  								{Name: "QueueSort"},
   210  							},
   211  						},
   212  						Bind: config.PluginSet{
   213  							Enabled: []config.Plugin{
   214  								{Name: "Bind1"},
   215  							},
   216  						},
   217  					},
   218  				},
   219  			},
   220  			wantErr: "scheduler name is needed",
   221  		},
   222  		{
   223  			name: "plugins required for profile",
   224  			cfgs: []config.KubeSchedulerProfile{
   225  				{
   226  					SchedulerName: "profile-1",
   227  				},
   228  			},
   229  			wantErr: "plugins required for profile",
   230  		},
   231  		{
   232  			name: "invalid framework configuration",
   233  			cfgs: []config.KubeSchedulerProfile{
   234  				{
   235  					SchedulerName: "invalid-profile",
   236  					Plugins: &config.Plugins{
   237  						QueueSort: config.PluginSet{
   238  							Enabled: []config.Plugin{
   239  								{Name: "QueueSort"},
   240  							},
   241  						},
   242  					},
   243  				},
   244  			},
   245  			wantErr: "at least one bind plugin is needed",
   246  		},
   247  	}
   248  	for _, tc := range cases {
   249  		t.Run(tc.name, func(t *testing.T) {
   250  			_, ctx := ktesting.NewTestContext(t)
   251  			ctx, cancel := context.WithCancel(ctx)
   252  			defer cancel()
   253  			m, err := NewMap(ctx, tc.cfgs, fakeRegistry, nilRecorderFactory)
   254  			if err := checkErr(err, tc.wantErr); err != nil {
   255  				t.Fatal(err)
   256  			}
   257  			if len(tc.wantErr) != 0 {
   258  				return
   259  			}
   260  			if len(m) != len(tc.cfgs) {
   261  				t.Errorf("got %d profiles, want %d", len(m), len(tc.cfgs))
   262  			}
   263  		})
   264  	}
   265  }
   266  
   267  type fakePlugin struct {
   268  	name string
   269  }
   270  
   271  func (p *fakePlugin) Name() string {
   272  	return p.name
   273  }
   274  
   275  func (p *fakePlugin) Less(*framework.QueuedPodInfo, *framework.QueuedPodInfo) bool {
   276  	return false
   277  }
   278  
   279  func (p *fakePlugin) Bind(context.Context, *framework.CycleState, *v1.Pod, string) *framework.Status {
   280  	return nil
   281  }
   282  
   283  func newFakePlugin(name string) func(ctx context.Context, object runtime.Object, handle framework.Handle) (framework.Plugin, error) {
   284  	return func(_ context.Context, _ runtime.Object, _ framework.Handle) (framework.Plugin, error) {
   285  		return &fakePlugin{name: name}, nil
   286  	}
   287  }
   288  
   289  func nilRecorderFactory(_ string) events.EventRecorder {
   290  	return nil
   291  }
   292  
   293  func checkErr(err error, wantErr string) error {
   294  	if len(wantErr) == 0 {
   295  		return err
   296  	}
   297  	if err == nil || !strings.Contains(err.Error(), wantErr) {
   298  		return fmt.Errorf("got error %q, want %q", err, wantErr)
   299  	}
   300  	return nil
   301  }
   302  

View as plain text