github.com/cilium/statedb@v0.3.2/part/quick_test.go (about)

     1  package part_test
     2  
     3  import (
     4  	"slices"
     5  	"testing"
     6  	"testing/quick"
     7  
     8  	"github.com/cilium/statedb/part"
     9  	"github.com/stretchr/testify/require"
    10  )
    11  
    12  var quickConfig = &quick.Config{
    13  	// Use a higher count in order to hit the Node256 cases.
    14  	MaxCount: 2000,
    15  }
    16  
    17  func TestQuick_InsertGetPrefix(t *testing.T) {
    18  	tree := part.New[string]()
    19  	insert := func(key, value string) any {
    20  		_, _, tree = tree.Insert([]byte(key), value)
    21  		return value
    22  	}
    23  
    24  	get := func(key, value string) any {
    25  		val, _, _ := tree.Get([]byte(key))
    26  		if val != value {
    27  			return val
    28  		}
    29  
    30  		iter, _ := tree.Prefix([]byte(key))
    31  		_, v, _ := iter.Next()
    32  		return v
    33  	}
    34  
    35  	require.NoError(t,
    36  		quick.CheckEqual(insert, get, quickConfig),
    37  	)
    38  }
    39  
    40  func TestQuick_IteratorReuse(t *testing.T) {
    41  	tree := part.New[string]()
    42  
    43  	iterate := func(key, value string, cloneFirst bool) bool {
    44  		_, _, tree = tree.Insert([]byte(key), value)
    45  		v, _, ok := tree.Get([]byte(key))
    46  		if !ok || value != v {
    47  			return false
    48  		}
    49  
    50  		prefixIter, _ := tree.Prefix([]byte(key))
    51  		iterators := []*part.Iterator[string]{
    52  			tree.LowerBound([]byte(key)),
    53  			prefixIter,
    54  		}
    55  
    56  		for _, iter := range iterators {
    57  			iter2 := iter.Clone()
    58  
    59  			collect := func(it *part.Iterator[string]) (out []string) {
    60  				for k, v, ok := it.Next(); ok; k, v, ok = it.Next() {
    61  					out = append(out, string(k)+"="+v)
    62  				}
    63  				return
    64  			}
    65  
    66  			var fst, snd []string
    67  			if cloneFirst {
    68  				snd = collect(iter2)
    69  				fst = collect(iter)
    70  			} else {
    71  				fst = collect(iter)
    72  				snd = collect(iter2)
    73  			}
    74  
    75  			if !slices.Equal(fst, snd) {
    76  				return false
    77  			}
    78  		}
    79  		return true
    80  	}
    81  
    82  	require.NoError(t,
    83  		quick.Check(iterate, quickConfig),
    84  	)
    85  }
    86  
    87  func TestQuick_Delete(t *testing.T) {
    88  	tree := part.New[string]()
    89  
    90  	do := func(key, value string, delete bool) bool {
    91  		_, _, tree = tree.Insert([]byte(key), value)
    92  		treeAfterInsert := tree
    93  		v, watch, ok := tree.Get([]byte(key))
    94  		if !ok || v != value {
    95  			t.Logf("value not in tree after insert")
    96  			return false
    97  		}
    98  
    99  		// delete some of the time to construct different variations of trees.
   100  		if delete {
   101  			_, _, tree = tree.Delete([]byte(key))
   102  			_, _, ok := tree.Get([]byte(key))
   103  			if ok {
   104  				t.Logf("value exists after delete")
   105  				return false
   106  			}
   107  
   108  			_, _, ok = treeAfterInsert.Get([]byte(key))
   109  			if !ok {
   110  				t.Logf("value deleted from original")
   111  			}
   112  
   113  			// Check that watch channel closed.
   114  			select {
   115  			case <-watch:
   116  			default:
   117  				t.Logf("watch channel not closed")
   118  				return false
   119  			}
   120  		}
   121  		return true
   122  	}
   123  
   124  	require.NoError(t, quick.Check(do, quickConfig))
   125  }
   126  
   127  func TestQuick_ClosedWatch(t *testing.T) {
   128  	tree := part.New[string]()
   129  	insert := func(key, value string) bool {
   130  		_, _, tree = tree.Insert([]byte(key), value)
   131  		treeAfterInsert := tree
   132  
   133  		val, watch, ok := tree.Get([]byte(key))
   134  		if !ok {
   135  			return false
   136  		}
   137  		if val != value {
   138  			return false
   139  		}
   140  
   141  		select {
   142  		case <-watch:
   143  			return false
   144  		default:
   145  		}
   146  
   147  		// Changing the key makes the channel close.
   148  		_, _, tree = tree.Insert([]byte(key), "x")
   149  		select {
   150  		case <-watch:
   151  		default:
   152  			t.Logf("channel not closed!")
   153  			return false
   154  		}
   155  
   156  		// Original tree unaffected.
   157  		val, _, ok = treeAfterInsert.Get([]byte(key))
   158  		if !ok || val != value {
   159  			t.Logf("original changed!")
   160  			return false
   161  		}
   162  
   163  		val, _, ok = tree.Get([]byte(key))
   164  		if !ok || val != "x" {
   165  			t.Logf("new tree does not have x!")
   166  			return false
   167  		}
   168  
   169  		return true
   170  	}
   171  
   172  	require.NoError(t, quick.Check(insert, quickConfig))
   173  }