...

Source file src/k8s.io/client-go/tools/cache/thread_safe_store_test.go

Documentation: k8s.io/client-go/tools/cache

     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 cache
    18  
    19  import (
    20  	"fmt"
    21  	"strings"
    22  	"testing"
    23  
    24  	"github.com/google/go-cmp/cmp"
    25  	"github.com/stretchr/testify/assert"
    26  )
    27  
    28  func TestThreadSafeStoreDeleteRemovesEmptySetsFromIndex(t *testing.T) {
    29  	testIndexer := "testIndexer"
    30  
    31  	indexers := Indexers{
    32  		testIndexer: func(obj interface{}) (strings []string, e error) {
    33  			indexes := []string{obj.(string)}
    34  			return indexes, nil
    35  		},
    36  	}
    37  
    38  	indices := Indices{}
    39  	store := NewThreadSafeStore(indexers, indices).(*threadSafeMap)
    40  
    41  	testKey := "testKey"
    42  
    43  	store.Add(testKey, testKey)
    44  
    45  	// Assumption check, there should be a set for the `testKey` with one element in the added index
    46  	set := store.index.indices[testIndexer][testKey]
    47  
    48  	if len(set) != 1 {
    49  		t.Errorf("Initial assumption of index backing string set having 1 element failed. Actual elements: %d", len(set))
    50  		return
    51  	}
    52  
    53  	store.Delete(testKey)
    54  	set, present := store.index.indices[testIndexer][testKey]
    55  
    56  	if present {
    57  		t.Errorf("Index backing string set not deleted from index. Set length: %d", len(set))
    58  	}
    59  }
    60  
    61  func TestThreadSafeStoreAddKeepsNonEmptySetPostDeleteFromIndex(t *testing.T) {
    62  	testIndexer := "testIndexer"
    63  	testIndex := "testIndex"
    64  
    65  	indexers := Indexers{
    66  		testIndexer: func(obj interface{}) (strings []string, e error) {
    67  			indexes := []string{testIndex}
    68  			return indexes, nil
    69  		},
    70  	}
    71  
    72  	indices := Indices{}
    73  	store := NewThreadSafeStore(indexers, indices).(*threadSafeMap)
    74  
    75  	store.Add("retain", "retain")
    76  	store.Add("delete", "delete")
    77  
    78  	// Assumption check, there should be a set for the `testIndex` with two elements
    79  	set := store.index.indices[testIndexer][testIndex]
    80  
    81  	if len(set) != 2 {
    82  		t.Errorf("Initial assumption of index backing string set having 2 elements failed. Actual elements: %d", len(set))
    83  		return
    84  	}
    85  
    86  	store.Delete("delete")
    87  	set, present := store.index.indices[testIndexer][testIndex]
    88  
    89  	if !present {
    90  		t.Errorf("Index backing string set erroneously deleted from index.")
    91  		return
    92  	}
    93  
    94  	if len(set) != 1 {
    95  		t.Errorf("Index backing string set has incorrect length, expect 1. Set length: %d", len(set))
    96  	}
    97  }
    98  
    99  func TestThreadSafeStoreIndexingFunctionsWithMultipleValues(t *testing.T) {
   100  	testIndexer := "testIndexer"
   101  
   102  	indexers := Indexers{
   103  		testIndexer: func(obj interface{}) ([]string, error) {
   104  			return strings.Split(obj.(string), ","), nil
   105  		},
   106  	}
   107  
   108  	indices := Indices{}
   109  	store := NewThreadSafeStore(indexers, indices).(*threadSafeMap)
   110  
   111  	store.Add("key1", "foo")
   112  	store.Add("key2", "bar")
   113  
   114  	assert := assert.New(t)
   115  
   116  	compare := func(key string, expected []string) error {
   117  		values := store.index.indices[testIndexer][key].List()
   118  		if cmp.Equal(values, expected) {
   119  			return nil
   120  		}
   121  		return fmt.Errorf("unexpected index for key %s, diff=%s", key, cmp.Diff(values, expected))
   122  	}
   123  
   124  	assert.NoError(compare("foo", []string{"key1"}))
   125  	assert.NoError(compare("bar", []string{"key2"}))
   126  
   127  	store.Update("key2", "foo,bar")
   128  
   129  	assert.NoError(compare("foo", []string{"key1", "key2"}))
   130  	assert.NoError(compare("bar", []string{"key2"}))
   131  
   132  	store.Update("key1", "foo,bar")
   133  
   134  	assert.NoError(compare("foo", []string{"key1", "key2"}))
   135  	assert.NoError(compare("bar", []string{"key1", "key2"}))
   136  
   137  	store.Add("key3", "foo,bar,baz")
   138  
   139  	assert.NoError(compare("foo", []string{"key1", "key2", "key3"}))
   140  	assert.NoError(compare("bar", []string{"key1", "key2", "key3"}))
   141  	assert.NoError(compare("baz", []string{"key3"}))
   142  
   143  	store.Update("key1", "foo")
   144  
   145  	assert.NoError(compare("foo", []string{"key1", "key2", "key3"}))
   146  	assert.NoError(compare("bar", []string{"key2", "key3"}))
   147  	assert.NoError(compare("baz", []string{"key3"}))
   148  
   149  	store.Update("key2", "bar")
   150  
   151  	assert.NoError(compare("foo", []string{"key1", "key3"}))
   152  	assert.NoError(compare("bar", []string{"key2", "key3"}))
   153  	assert.NoError(compare("baz", []string{"key3"}))
   154  
   155  	store.Delete("key1")
   156  
   157  	assert.NoError(compare("foo", []string{"key3"}))
   158  	assert.NoError(compare("bar", []string{"key2", "key3"}))
   159  	assert.NoError(compare("baz", []string{"key3"}))
   160  
   161  	store.Delete("key3")
   162  
   163  	assert.NoError(compare("foo", []string{}))
   164  	assert.NoError(compare("bar", []string{"key2"}))
   165  	assert.NoError(compare("baz", []string{}))
   166  }
   167  
   168  func BenchmarkIndexer(b *testing.B) {
   169  	testIndexer := "testIndexer"
   170  
   171  	indexers := Indexers{
   172  		testIndexer: func(obj interface{}) (strings []string, e error) {
   173  			indexes := []string{obj.(string)}
   174  			return indexes, nil
   175  		},
   176  	}
   177  
   178  	indices := Indices{}
   179  	store := NewThreadSafeStore(indexers, indices).(*threadSafeMap)
   180  
   181  	// The following benchmark imitates what is happening in indexes
   182  	// used in storage layer, where indexing is mostly static (e.g.
   183  	// indexing objects by their (namespace, name)).
   184  	// The 5000 number imitates indexing nodes in 5000-node cluster.
   185  	objectCount := 5000
   186  	objects := make([]string, 0, 5000)
   187  	for i := 0; i < objectCount; i++ {
   188  		objects = append(objects, fmt.Sprintf("object-number-%d", i))
   189  	}
   190  
   191  	b.ResetTimer()
   192  	for i := 0; i < b.N; i++ {
   193  		store.Update(objects[i%objectCount], objects[i%objectCount])
   194  	}
   195  }
   196  

View as plain text