go.ligato.io/vpp-agent/v3@v3.5.0/plugins/kvscheduler/internal/test/descriptor.go (about)

     1  // Copyright (c) 2018 Cisco and/or its affiliates.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at:
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package test
    16  
    17  import (
    18  	"strings"
    19  
    20  	"go.ligato.io/cn-infra/v2/idxmap"
    21  	"google.golang.org/protobuf/proto"
    22  
    23  	. "go.ligato.io/vpp-agent/v3/plugins/kvscheduler/api"
    24  )
    25  
    26  // WithoutOp references operation to leave undefined in the MockDescriptor.
    27  type WithoutOp int
    28  
    29  const (
    30  	// WithoutCreate tells MockDescriptor to leave Create as nil.
    31  	WithoutCreate WithoutOp = iota
    32  	// WithoutUpdate tells MockDescriptor to leave Update as nil.
    33  	WithoutUpdate
    34  	// WithoutDelete tells MockDescriptor to leave Delete as nil.
    35  	WithoutDelete
    36  	// WithoutRetrieve tells MockDescriptor to leave Retrieve as nil.
    37  	WithoutRetrieve
    38  )
    39  
    40  // mockDescriptor implements KVDescriptor for UTs.
    41  type mockDescriptor struct {
    42  	nextIndex int
    43  	args      *KVDescriptor
    44  	sb        *MockSouthbound
    45  }
    46  
    47  // NewMockDescriptor creates a new instance of Mock Descriptor.
    48  func NewMockDescriptor(args *KVDescriptor, sb *MockSouthbound, firstFreeIndex int, withoutOps ...WithoutOp) *KVDescriptor {
    49  	mock := &mockDescriptor{
    50  		nextIndex: firstFreeIndex,
    51  		args:      args,
    52  		sb:        sb,
    53  	}
    54  	descriptor := &KVDescriptor{
    55  		Name:                 args.Name,
    56  		KeySelector:          args.KeySelector,
    57  		ValueTypeName:        args.ValueTypeName,
    58  		ValueComparator:      args.ValueComparator,
    59  		KeyLabel:             args.KeyLabel,
    60  		NBKeyPrefix:          args.NBKeyPrefix,
    61  		WithMetadata:         args.WithMetadata,
    62  		Validate:             args.Validate,
    63  		IsRetriableFailure:   args.IsRetriableFailure,
    64  		UpdateWithRecreate:   args.UpdateWithRecreate,
    65  		Dependencies:         args.Dependencies,
    66  		RetrieveDependencies: args.RetrieveDependencies,
    67  	}
    68  	if args.WithMetadata {
    69  		descriptor.MetadataMapFactory = func() idxmap.NamedMappingRW {
    70  			return NewNameToInteger(args.Name)
    71  		}
    72  		descriptor.KeyLabel = func(key string) string {
    73  			return strings.TrimPrefix(key, args.NBKeyPrefix)
    74  		}
    75  	}
    76  	if args.DerivedValues != nil {
    77  		descriptor.DerivedValues = mock.DerivedValues
    78  	}
    79  
    80  	// operations that can be left undefined:
    81  	withoutMap := make(map[WithoutOp]struct{})
    82  	for _, withoutOp := range withoutOps {
    83  		withoutMap[withoutOp] = struct{}{}
    84  	}
    85  	if _, withoutCreate := withoutMap[WithoutCreate]; !withoutCreate {
    86  		descriptor.Create = mock.Create
    87  	}
    88  	if _, withoutDelete := withoutMap[WithoutDelete]; !withoutDelete {
    89  		descriptor.Delete = mock.Delete
    90  	}
    91  	if _, withoutUpdate := withoutMap[WithoutUpdate]; !withoutUpdate {
    92  		descriptor.Update = mock.Update
    93  	}
    94  	if _, withoutRetrieve := withoutMap[WithoutRetrieve]; !withoutRetrieve {
    95  		descriptor.Retrieve = mock.Retrieve
    96  	}
    97  	return descriptor
    98  }
    99  
   100  // validateKey tests predicate for a key that should hold.
   101  func (md *mockDescriptor) validateKey(key string, predicate bool) {
   102  	if !predicate && md.sb != nil {
   103  		md.sb.registerKeyWithInvalidData(key)
   104  	}
   105  }
   106  
   107  // equalValues compares two values for equality
   108  func (md *mockDescriptor) equalValues(key string, v1, v2 proto.Message) bool {
   109  	if md.args.ValueComparator != nil {
   110  		return md.args.ValueComparator(key, v1, v2)
   111  	}
   112  	return proto.Equal(v1, v2)
   113  }
   114  
   115  // Create executes create operation in the mock SB.
   116  func (md *mockDescriptor) Create(key string, value proto.Message) (metadata Metadata, err error) {
   117  	md.validateKey(key, md.args.KeySelector(key))
   118  	withMeta := md.sb != nil && md.args.WithMetadata && !md.sb.isKeyDerived(key)
   119  	if withMeta {
   120  		metadata = &OnlyInteger{md.nextIndex}
   121  	}
   122  	if md.sb != nil {
   123  		md.validateKey(key, md.sb.GetValue(key) == nil)
   124  		err = md.sb.executeChange(md.args.Name, MockCreate, key, value, metadata)
   125  	}
   126  	if err == nil && withMeta {
   127  		md.nextIndex++
   128  	}
   129  	return metadata, err
   130  }
   131  
   132  // Delete executes del operation in the mock SB.
   133  func (md *mockDescriptor) Delete(key string, value proto.Message, metadata Metadata) (err error) {
   134  	md.validateKey(key, md.args.KeySelector(key))
   135  	if md.sb != nil {
   136  		kv := md.sb.GetValue(key)
   137  		md.validateKey(key, kv != nil)
   138  		if md.sb.isKeyDerived(key) {
   139  			// re-generated on refresh
   140  			md.validateKey(key, md.equalValues(key, kv.Value, value))
   141  		} else {
   142  			md.validateKey(key, kv.Value == value)
   143  		}
   144  		md.validateKey(key, kv.Metadata == metadata)
   145  		err = md.sb.executeChange(md.args.Name, MockDelete, key, nil, metadata)
   146  	}
   147  	return err
   148  }
   149  
   150  // Update executes update operation in the mock SB.
   151  func (md *mockDescriptor) Update(key string, oldValue, newValue proto.Message, oldMetadata Metadata) (newMetadata Metadata, err error) {
   152  	md.validateKey(key, md.args.KeySelector(key))
   153  	newMetadata = oldMetadata
   154  	if md.sb != nil {
   155  		kv := md.sb.GetValue(key)
   156  		md.validateKey(key, kv != nil)
   157  		if md.sb.isKeyDerived(key) {
   158  			// re-generated on refresh
   159  			md.validateKey(key, md.equalValues(key, kv.Value, oldValue))
   160  		} else {
   161  			md.validateKey(key, kv.Value == oldValue)
   162  		}
   163  		md.validateKey(key, kv.Metadata == oldMetadata)
   164  		err = md.sb.executeChange(md.args.Name, MockUpdate, key, newValue, newMetadata)
   165  	}
   166  	return newMetadata, err
   167  }
   168  
   169  // Dependencies uses provided DerValuesBuilder.
   170  func (md *mockDescriptor) DerivedValues(key string, value proto.Message) []KeyValuePair {
   171  	md.validateKey(key, md.args.KeySelector(key))
   172  	if md.args.DerivedValues != nil {
   173  		derivedKVs := md.args.DerivedValues(key, value)
   174  		if md.sb != nil {
   175  			for _, kv := range derivedKVs {
   176  				md.sb.registerDerivedKey(kv.Key)
   177  			}
   178  		}
   179  		return derivedKVs
   180  	}
   181  	return nil
   182  }
   183  
   184  // Retrieve returns non-derived values currently set in the mock SB.
   185  func (md *mockDescriptor) Retrieve(correlate []KVWithMetadata) ([]KVWithMetadata, error) {
   186  	if md.sb == nil {
   187  		return nil, nil
   188  	}
   189  	return md.sb.retrieve(md.args.Name, correlate, md.args.KeySelector)
   190  }