...

Source file src/k8s.io/kubernetes/pkg/scheduler/framework/cycle_state_test.go

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

     1  /*
     2  Copyright 2019 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 framework
    18  
    19  import (
    20  	"fmt"
    21  	"testing"
    22  )
    23  
    24  type fakeData struct {
    25  	data string
    26  }
    27  
    28  func (f *fakeData) Clone() StateData {
    29  	copy := &fakeData{
    30  		data: f.data,
    31  	}
    32  	return copy
    33  }
    34  
    35  var key StateKey = "fakedata_key"
    36  
    37  // createCycleStateWithFakeData creates *CycleState with fakeData.
    38  // The given data is used in stored fakeData.
    39  func createCycleStateWithFakeData(data string, recordPluginMetrics bool) *CycleState {
    40  	c := NewCycleState()
    41  	c.Write(key, &fakeData{
    42  		data: data,
    43  	})
    44  	c.SetRecordPluginMetrics(recordPluginMetrics)
    45  	return c
    46  }
    47  
    48  // isCycleStateEqual returns whether two CycleState, which has fakeData in storage, is equal or not.
    49  // And if they are not equal, returns message which shows why not equal.
    50  func isCycleStateEqual(a, b *CycleState) (bool, string) {
    51  	if a == nil && b == nil {
    52  		return true, ""
    53  	}
    54  	if a == nil || b == nil {
    55  		return false, fmt.Sprintf("one CycleState is nil, but another one is not nil. A: %v, B: %v", a, b)
    56  	}
    57  
    58  	if a.recordPluginMetrics != b.recordPluginMetrics {
    59  		return false, fmt.Sprintf("CycleState A and B have a different recordPluginMetrics. A: %v, B: %v", a.recordPluginMetrics, b.recordPluginMetrics)
    60  	}
    61  
    62  	var msg string
    63  	isEqual := true
    64  	countA := 0
    65  	a.storage.Range(func(k, v1 interface{}) bool {
    66  		countA++
    67  		v2, ok := b.storage.Load(k)
    68  		if !ok {
    69  			isEqual = false
    70  			msg = fmt.Sprintf("CycleState B doesn't have the data which CycleState A has. key: %v, data: %v", k, v1)
    71  			return false
    72  		}
    73  
    74  		typed1, ok1 := v1.(*fakeData)
    75  		typed2, ok2 := v2.(*fakeData)
    76  		if !ok1 || !ok2 {
    77  			isEqual = false
    78  			msg = fmt.Sprintf("CycleState has the data which is not type *fakeData.")
    79  			return false
    80  		}
    81  
    82  		if typed1.data != typed2.data {
    83  			isEqual = false
    84  			msg = fmt.Sprintf("CycleState B has a different data on key %v. A: %v, B: %v", k, typed1.data, typed2.data)
    85  			return false
    86  		}
    87  
    88  		return true
    89  	})
    90  
    91  	if !isEqual {
    92  		return false, msg
    93  	}
    94  
    95  	countB := 0
    96  	b.storage.Range(func(k, _ interface{}) bool {
    97  		countB++
    98  		return true
    99  	})
   100  
   101  	if countA != countB {
   102  		return false, fmt.Sprintf("two Cyclestates have different numbers of data. A: %v, B: %v", countA, countB)
   103  	}
   104  
   105  	return true, ""
   106  }
   107  
   108  func TestCycleStateClone(t *testing.T) {
   109  	tests := []struct {
   110  		name            string
   111  		state           *CycleState
   112  		wantClonedState *CycleState
   113  	}{
   114  		{
   115  			name:            "clone with recordPluginMetrics true",
   116  			state:           createCycleStateWithFakeData("data", true),
   117  			wantClonedState: createCycleStateWithFakeData("data", true),
   118  		},
   119  		{
   120  			name:            "clone with recordPluginMetrics false",
   121  			state:           createCycleStateWithFakeData("data", false),
   122  			wantClonedState: createCycleStateWithFakeData("data", false),
   123  		},
   124  		{
   125  			name:            "clone with nil CycleState",
   126  			state:           nil,
   127  			wantClonedState: nil,
   128  		},
   129  	}
   130  
   131  	for _, tt := range tests {
   132  		t.Run(tt.name, func(t *testing.T) {
   133  			state := tt.state
   134  			stateCopy := state.Clone()
   135  
   136  			if isEqual, msg := isCycleStateEqual(stateCopy, tt.wantClonedState); !isEqual {
   137  				t.Errorf("unexpected cloned state: %v", msg)
   138  			}
   139  
   140  			if state == nil || stateCopy == nil {
   141  				// not need to run the rest check in this case.
   142  				return
   143  			}
   144  
   145  			stateCopy.Write(key, &fakeData{data: "modified"})
   146  			if isEqual, _ := isCycleStateEqual(state, stateCopy); isEqual {
   147  				t.Errorf("the change for a cloned state should not affect the original state.")
   148  			}
   149  		})
   150  	}
   151  }
   152  

View as plain text