github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/registry/resolver/cache/cache_test.go (about)

     1  package cache
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  	"fmt"
     7  	"math/rand"
     8  	"strconv"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/assert"
    12  	"github.com/stretchr/testify/require"
    13  )
    14  
    15  func TestOperatorCacheConcurrency(t *testing.T) {
    16  	const (
    17  		NWorkers = 64
    18  	)
    19  
    20  	sp := make(StaticSourceProvider)
    21  	var keys []SourceKey
    22  	for i := 0; i < 128; i++ {
    23  		for j := 0; j < 8; j++ {
    24  			key := SourceKey{Namespace: strconv.Itoa(i), Name: strconv.Itoa(j)}
    25  			keys = append(keys, key)
    26  			sp[key] = &Snapshot{
    27  				Entries: []*Entry{
    28  					{Name: fmt.Sprintf("%s/%s", key.Namespace, key.Name)},
    29  				},
    30  			}
    31  		}
    32  	}
    33  
    34  	c := New(sp)
    35  
    36  	errs := make(chan error)
    37  	for w := 0; w < NWorkers; w++ {
    38  		go func(w int) (result error) {
    39  			defer func() { errs <- result }()
    40  
    41  			rand := rand.New(rand.NewSource(int64(w)))
    42  			indices := rand.Perm(len(keys))[:8]
    43  			namespaces := make([]string, len(indices))
    44  			for i, index := range indices {
    45  				namespaces[i] = keys[index].Namespace
    46  			}
    47  
    48  			nc := c.Namespaced(namespaces...)
    49  			for _, index := range indices {
    50  				name := fmt.Sprintf("%s/%s", keys[index].Namespace, keys[index].Name)
    51  				operators := nc.Find(CSVNamePredicate(name))
    52  				if len(operators) != 1 {
    53  					return fmt.Errorf("expected 1 operator, got %d", len(operators))
    54  				}
    55  			}
    56  
    57  			return nil
    58  		}(w)
    59  	}
    60  
    61  	for w := 0; w < NWorkers; w++ {
    62  		assert.NoError(t, <-errs)
    63  	}
    64  }
    65  
    66  func TestOperatorCacheExpiration(t *testing.T) {
    67  	key := SourceKey{Namespace: "dummynamespace", Name: "dummyname"}
    68  	ssp := make(StaticSourceProvider)
    69  	c := New(ssp)
    70  
    71  	ssp[key] = &Snapshot{
    72  		Entries: []*Entry{
    73  			{Name: "v1"},
    74  		},
    75  		Valid: ValidOnce(),
    76  	}
    77  	require.Len(t, c.Namespaced("dummynamespace").Catalog(key).Find(CSVNamePredicate("v1")), 1)
    78  
    79  	ssp[key] = &Snapshot{
    80  		Entries: []*Entry{
    81  			{Name: "v2"},
    82  		},
    83  	}
    84  	require.Len(t, c.Namespaced("dummynamespace").Catalog(key).Find(CSVNamePredicate("v1")), 0)
    85  }
    86  
    87  func TestOperatorCacheReuse(t *testing.T) {
    88  	key := SourceKey{Namespace: "dummynamespace", Name: "dummyname"}
    89  	ssp := make(StaticSourceProvider)
    90  	c := New(ssp)
    91  
    92  	ssp[key] = &Snapshot{
    93  		Entries: []*Entry{
    94  			{Name: "v1"},
    95  		},
    96  	}
    97  	require.Len(t, c.Namespaced("dummynamespace").Catalog(key).Find(CSVNamePredicate("v1")), 1)
    98  
    99  	ssp[key] = &Snapshot{
   100  		Entries: []*Entry{
   101  			{Name: "v2"},
   102  		},
   103  	}
   104  	require.Len(t, c.Namespaced("dummynamespace").Catalog(key).Find(CSVNamePredicate("v1")), 1)
   105  }
   106  
   107  func TestCatalogSnapshotValid(t *testing.T) {
   108  	type tc struct {
   109  		Name     string
   110  		Snapshot *Snapshot
   111  		Error    error
   112  		Expected bool
   113  	}
   114  
   115  	for _, tt := range []tc{
   116  		{
   117  			Name: "invalidated",
   118  			Snapshot: &Snapshot{
   119  				Valid: ValidOnce(),
   120  			},
   121  			Error:    nil,
   122  			Expected: false,
   123  		},
   124  		{
   125  			Name:     "valid",
   126  			Snapshot: &Snapshot{}, // valid forever
   127  			Error:    nil,
   128  			Expected: true,
   129  		},
   130  		{
   131  			Name:     "nil snapshot and non-nil error",
   132  			Snapshot: nil,
   133  			Error:    errors.New(""),
   134  			Expected: false,
   135  		},
   136  		{
   137  			Name:     "non-nil snapshot and non-nil error",
   138  			Snapshot: &Snapshot{},
   139  			Error:    errors.New(""),
   140  			Expected: false,
   141  		},
   142  		{
   143  			Name:     "nil snapshot and nil error",
   144  			Snapshot: nil,
   145  			Error:    nil,
   146  			Expected: false,
   147  		},
   148  	} {
   149  		t.Run(tt.Name, func(t *testing.T) {
   150  			s := snapshotHeader{
   151  				snapshot: tt.Snapshot,
   152  				err:      tt.Error,
   153  			}
   154  			assert.Equal(t, tt.Expected, s.Valid())
   155  		})
   156  	}
   157  }
   158  
   159  func TestCatalogSnapshotFind(t *testing.T) {
   160  	type tc struct {
   161  		Name      string
   162  		Predicate Predicate
   163  		Operators []*Entry
   164  		Expected  []*Entry
   165  	}
   166  
   167  	for _, tt := range []tc{
   168  		{
   169  			Name: "nothing satisfies predicate",
   170  			Predicate: OperatorPredicateTestFunc(func(*Entry) bool {
   171  				return false
   172  			}),
   173  			Operators: []*Entry{
   174  				{Name: "a"},
   175  				{Name: "b"},
   176  				{Name: "c"},
   177  			},
   178  			Expected: nil,
   179  		},
   180  		{
   181  			Name: "no operators in snapshot",
   182  			Predicate: OperatorPredicateTestFunc(func(*Entry) bool {
   183  				return true
   184  			}),
   185  			Operators: nil,
   186  			Expected:  nil,
   187  		},
   188  		{
   189  			Name: "everything satisfies predicate",
   190  			Predicate: OperatorPredicateTestFunc(func(*Entry) bool {
   191  				return true
   192  			}),
   193  			Operators: []*Entry{
   194  				{Name: "a"},
   195  				{Name: "b"},
   196  				{Name: "c"},
   197  			},
   198  			Expected: []*Entry{
   199  				{Name: "a"},
   200  				{Name: "b"},
   201  				{Name: "c"},
   202  			},
   203  		},
   204  		{
   205  			Name: "some satisfy predicate",
   206  			Predicate: OperatorPredicateTestFunc(func(o *Entry) bool {
   207  				return o.Name != "a"
   208  			}),
   209  			Operators: []*Entry{
   210  				{Name: "a"},
   211  				{Name: "b"},
   212  				{Name: "c"},
   213  			},
   214  			Expected: []*Entry{
   215  				{Name: "b"},
   216  				{Name: "c"},
   217  			},
   218  		},
   219  	} {
   220  		t.Run(tt.Name, func(t *testing.T) {
   221  			s := snapshotHeader{snapshot: &Snapshot{Entries: tt.Operators}}
   222  			assert.Equal(t, tt.Expected, s.Find(tt.Predicate))
   223  		})
   224  	}
   225  }
   226  
   227  type ErrorSource struct {
   228  	Error error
   229  }
   230  
   231  func (s ErrorSource) Snapshot(context.Context) (*Snapshot, error) {
   232  	return nil, s.Error
   233  }
   234  
   235  func TestNamespaceOperatorCacheError(t *testing.T) {
   236  	key := SourceKey{Namespace: "dummynamespace", Name: "dummyname"}
   237  	c := New(StaticSourceProvider{
   238  		key: ErrorSource{Error: errors.New("testing")},
   239  	})
   240  
   241  	require.EqualError(t, c.Namespaced("dummynamespace").Error(), "error using catalogsource dummynamespace/dummyname: testing")
   242  }