152 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			152 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Go
		
	
	
	
/*
 | 
						|
Copyright 2019 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 framework
 | 
						|
 | 
						|
import (
 | 
						|
	"fmt"
 | 
						|
	"testing"
 | 
						|
)
 | 
						|
 | 
						|
type fakeData struct {
 | 
						|
	data string
 | 
						|
}
 | 
						|
 | 
						|
func (f *fakeData) Clone() StateData {
 | 
						|
	copy := &fakeData{
 | 
						|
		data: f.data,
 | 
						|
	}
 | 
						|
	return copy
 | 
						|
}
 | 
						|
 | 
						|
var key StateKey = "fakedata_key"
 | 
						|
 | 
						|
// createCycleStateWithFakeData creates *CycleState with fakeData.
 | 
						|
// The given data is used in stored fakeData.
 | 
						|
func createCycleStateWithFakeData(data string, recordPluginMetrics bool) *CycleState {
 | 
						|
	c := NewCycleState()
 | 
						|
	c.Write(key, &fakeData{
 | 
						|
		data: data,
 | 
						|
	})
 | 
						|
	c.SetRecordPluginMetrics(recordPluginMetrics)
 | 
						|
	return c
 | 
						|
}
 | 
						|
 | 
						|
// isCycleStateEqual returns whether two CycleState, which has fakeData in storage, is equal or not.
 | 
						|
// And if they are not equal, returns message which shows why not equal.
 | 
						|
func isCycleStateEqual(a, b *CycleState) (bool, string) {
 | 
						|
	if a == nil && b == nil {
 | 
						|
		return true, ""
 | 
						|
	}
 | 
						|
	if a == nil || b == nil {
 | 
						|
		return false, fmt.Sprintf("one CycleState is nil, but another one is not nil. A: %v, B: %v", a, b)
 | 
						|
	}
 | 
						|
 | 
						|
	if a.recordPluginMetrics != b.recordPluginMetrics {
 | 
						|
		return false, fmt.Sprintf("CycleState A and B have a different recordPluginMetrics. A: %v, B: %v", a.recordPluginMetrics, b.recordPluginMetrics)
 | 
						|
	}
 | 
						|
 | 
						|
	var msg string
 | 
						|
	isEqual := true
 | 
						|
	countA := 0
 | 
						|
	a.storage.Range(func(k, v1 interface{}) bool {
 | 
						|
		countA++
 | 
						|
		v2, ok := b.storage.Load(k)
 | 
						|
		if !ok {
 | 
						|
			isEqual = false
 | 
						|
			msg = fmt.Sprintf("CycleState B doesn't have the data which CycleState A has. key: %v, data: %v", k, v1)
 | 
						|
			return false
 | 
						|
		}
 | 
						|
 | 
						|
		typed1, ok1 := v1.(*fakeData)
 | 
						|
		typed2, ok2 := v2.(*fakeData)
 | 
						|
		if !ok1 || !ok2 {
 | 
						|
			isEqual = false
 | 
						|
			msg = fmt.Sprintf("CycleState has the data which is not type *fakeData.")
 | 
						|
			return false
 | 
						|
		}
 | 
						|
 | 
						|
		if typed1.data != typed2.data {
 | 
						|
			isEqual = false
 | 
						|
			msg = fmt.Sprintf("CycleState B has a different data on key %v. A: %v, B: %v", k, typed1.data, typed2.data)
 | 
						|
			return false
 | 
						|
		}
 | 
						|
 | 
						|
		return true
 | 
						|
	})
 | 
						|
 | 
						|
	if !isEqual {
 | 
						|
		return false, msg
 | 
						|
	}
 | 
						|
 | 
						|
	countB := 0
 | 
						|
	b.storage.Range(func(k, _ interface{}) bool {
 | 
						|
		countB++
 | 
						|
		return true
 | 
						|
	})
 | 
						|
 | 
						|
	if countA != countB {
 | 
						|
		return false, fmt.Sprintf("two Cyclestates have different numbers of data. A: %v, B: %v", countA, countB)
 | 
						|
	}
 | 
						|
 | 
						|
	return true, ""
 | 
						|
}
 | 
						|
 | 
						|
func TestCycleStateClone(t *testing.T) {
 | 
						|
	tests := []struct {
 | 
						|
		name            string
 | 
						|
		state           *CycleState
 | 
						|
		wantClonedState *CycleState
 | 
						|
	}{
 | 
						|
		{
 | 
						|
			name:            "clone with recordPluginMetrics true",
 | 
						|
			state:           createCycleStateWithFakeData("data", true),
 | 
						|
			wantClonedState: createCycleStateWithFakeData("data", true),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "clone with recordPluginMetrics false",
 | 
						|
			state:           createCycleStateWithFakeData("data", false),
 | 
						|
			wantClonedState: createCycleStateWithFakeData("data", false),
 | 
						|
		},
 | 
						|
		{
 | 
						|
			name:            "clone with nil CycleState",
 | 
						|
			state:           nil,
 | 
						|
			wantClonedState: nil,
 | 
						|
		},
 | 
						|
	}
 | 
						|
 | 
						|
	for _, tt := range tests {
 | 
						|
		t.Run(tt.name, func(t *testing.T) {
 | 
						|
			state := tt.state
 | 
						|
			stateCopy := state.Clone()
 | 
						|
 | 
						|
			if isEqual, msg := isCycleStateEqual(stateCopy, tt.wantClonedState); !isEqual {
 | 
						|
				t.Errorf("unexpected cloned state: %v", msg)
 | 
						|
			}
 | 
						|
 | 
						|
			if state == nil || stateCopy == nil {
 | 
						|
				// not need to run the rest check in this case.
 | 
						|
				return
 | 
						|
			}
 | 
						|
 | 
						|
			stateCopy.Write(key, &fakeData{data: "modified"})
 | 
						|
			if isEqual, _ := isCycleStateEqual(state, stateCopy); isEqual {
 | 
						|
				t.Errorf("the change for a cloned state should not affect the original state.")
 | 
						|
			}
 | 
						|
		})
 | 
						|
	}
 | 
						|
}
 |