github.com/operator-framework/operator-lifecycle-manager@v0.30.0/pkg/controller/operators/olm/groups_test.go (about)

     1  package olm
     2  
     3  import (
     4  	"strings"
     5  	"testing"
     6  
     7  	operatorsv1 "github.com/operator-framework/api/pkg/operators/v1"
     8  	opregistry "github.com/operator-framework/operator-registry/pkg/registry"
     9  	"github.com/stretchr/testify/require"
    10  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    11  
    12  	"github.com/operator-framework/operator-lifecycle-manager/pkg/controller/registry/resolver/cache"
    13  )
    14  
    15  func buildAPIOperatorGroup(namespace, name string, targets []string, gvks []string) *operatorsv1.OperatorGroup {
    16  	return &operatorsv1.OperatorGroup{
    17  		ObjectMeta: metav1.ObjectMeta{
    18  			Namespace: namespace,
    19  			Name:      name,
    20  			Annotations: map[string]string{
    21  				operatorsv1.OperatorGroupProvidedAPIsAnnotationKey: strings.Join(gvks, ","),
    22  			},
    23  		},
    24  		Status: operatorsv1.OperatorGroupStatus{
    25  			Namespaces: targets,
    26  		},
    27  	}
    28  }
    29  func TestNewOperatorGroup(t *testing.T) {
    30  	tests := []struct {
    31  		name string
    32  		in   *operatorsv1.OperatorGroup
    33  		want *OperatorGroup
    34  	}{
    35  		{
    36  			name: "NoTargetNamespaces/NoProvidedAPIs",
    37  			in:   buildAPIOperatorGroup("ns", "empty-group", nil, nil),
    38  			want: &OperatorGroup{
    39  				namespace:    "ns",
    40  				name:         "empty-group",
    41  				targets:      make(NamespaceSet),
    42  				providedAPIs: make(cache.APISet),
    43  			},
    44  		},
    45  		{
    46  			name: "OneTargetNamespace/NoProvidedAPIs",
    47  			in:   buildAPIOperatorGroup("ns", "empty-group", []string{"ns-1"}, nil),
    48  			want: &OperatorGroup{
    49  				namespace: "ns",
    50  				name:      "empty-group",
    51  				targets: NamespaceSet{
    52  					"ns":   {},
    53  					"ns-1": {},
    54  				},
    55  				providedAPIs: make(cache.APISet),
    56  			},
    57  		},
    58  		{
    59  			name: "OwnTargetNamespace/NoProvidedAPIs",
    60  			in:   buildAPIOperatorGroup("ns", "empty-group", []string{"ns"}, nil),
    61  			want: &OperatorGroup{
    62  				namespace: "ns",
    63  				name:      "empty-group",
    64  				targets: NamespaceSet{
    65  					"ns": {},
    66  				},
    67  				providedAPIs: make(cache.APISet),
    68  			},
    69  		},
    70  		{
    71  			name: "MultipleTargetNamespaces/NoProvidedAPIs",
    72  			in:   buildAPIOperatorGroup("ns", "empty-group", []string{"ns-1", "ns-2"}, nil),
    73  			want: &OperatorGroup{
    74  				namespace: "ns",
    75  				name:      "empty-group",
    76  				targets: NamespaceSet{
    77  					"ns":   {},
    78  					"ns-1": {},
    79  					"ns-2": {},
    80  				},
    81  				providedAPIs: make(cache.APISet),
    82  			},
    83  		},
    84  		{
    85  			name: "AllTargetNamespaces/NoProvidedAPIs",
    86  			in:   buildAPIOperatorGroup("ns", "empty-group", []string{metav1.NamespaceAll}, nil),
    87  			want: &OperatorGroup{
    88  				namespace: "ns",
    89  				name:      "empty-group",
    90  				targets: NamespaceSet{
    91  					metav1.NamespaceAll: {},
    92  				},
    93  				providedAPIs: make(cache.APISet),
    94  			},
    95  		},
    96  		{
    97  			name: "OneTargetNamespace/OneProvidedAPI",
    98  			in:   buildAPIOperatorGroup("ns", "group", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
    99  			want: &OperatorGroup{
   100  				namespace: "ns",
   101  				name:      "group",
   102  				targets: NamespaceSet{
   103  					"ns":   {},
   104  					"ns-1": {},
   105  				},
   106  				providedAPIs: cache.APISet{
   107  					opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   108  				},
   109  			},
   110  		},
   111  		{
   112  			name: "OneTargetNamespace/BadProvidedAPI",
   113  			in:   buildAPIOperatorGroup("ns", "group", []string{"ns-1"}, []string{"Goose.v1alpha1"}),
   114  			want: &OperatorGroup{
   115  				namespace: "ns",
   116  				name:      "group",
   117  				targets: NamespaceSet{
   118  					"ns":   {},
   119  					"ns-1": {},
   120  				},
   121  				providedAPIs: make(cache.APISet),
   122  			},
   123  		},
   124  		{
   125  			name: "OneTargetNamespace/MultipleProvidedAPIs/OneBad",
   126  			in:   buildAPIOperatorGroup("ns", "group", []string{"ns-1"}, []string{"Goose.v1alpha1,Moose.v1alpha1.mammals.com"}),
   127  			want: &OperatorGroup{
   128  				namespace: "ns",
   129  				name:      "group",
   130  				targets: NamespaceSet{
   131  					"ns":   {},
   132  					"ns-1": {},
   133  				},
   134  				providedAPIs: cache.APISet{
   135  					opregistry.APIKey{Group: "mammals.com", Version: "v1alpha1", Kind: "Moose"}: {},
   136  				},
   137  			},
   138  		},
   139  		{
   140  			name: "OneTargetNamespace/MultipleProvidedAPIs",
   141  			in:   buildAPIOperatorGroup("ns", "group", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com,Moose.v1alpha1.mammals.com"}),
   142  			want: &OperatorGroup{
   143  				namespace: "ns",
   144  				name:      "group",
   145  				targets: NamespaceSet{
   146  					"ns":   {},
   147  					"ns-1": {},
   148  				},
   149  				providedAPIs: cache.APISet{
   150  					opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}:   {},
   151  					opregistry.APIKey{Group: "mammals.com", Version: "v1alpha1", Kind: "Moose"}: {},
   152  				},
   153  			},
   154  		},
   155  	}
   156  
   157  	for _, tt := range tests {
   158  		t.Run(tt.name, func(t *testing.T) {
   159  			group := NewOperatorGroup(tt.in)
   160  			require.NotNil(t, group)
   161  			require.EqualValues(t, tt.want, group)
   162  		})
   163  	}
   164  }
   165  
   166  func TestNamespaceSetIntersection(t *testing.T) {
   167  	type input struct {
   168  		left  NamespaceSet
   169  		right NamespaceSet
   170  	}
   171  	tests := []struct {
   172  		name string
   173  		in   input
   174  		want NamespaceSet
   175  	}{
   176  		{
   177  			name: "EmptySets",
   178  			in: input{
   179  				left:  make(NamespaceSet),
   180  				right: make(NamespaceSet),
   181  			},
   182  			want: make(NamespaceSet),
   183  		},
   184  		{
   185  			name: "EmptyLeft/MultipleRight/NoIntersection",
   186  			in: input{
   187  				left: make(NamespaceSet),
   188  				right: NamespaceSet{
   189  					"ns":   {},
   190  					"ns-1": {},
   191  					"ns-2": {},
   192  				},
   193  			},
   194  			want: make(NamespaceSet),
   195  		},
   196  		{
   197  			name: "MultipleLeft/EmptyRight/NoIntersection",
   198  			in: input{
   199  				left: NamespaceSet{
   200  					"ns":   {},
   201  					"ns-1": {},
   202  					"ns-2": {},
   203  				},
   204  				right: make(NamespaceSet),
   205  			},
   206  			want: make(NamespaceSet),
   207  		},
   208  		{
   209  			name: "OneLeft/OneRight/Intersection",
   210  			in: input{
   211  				left: NamespaceSet{
   212  					"ns": {},
   213  				},
   214  				right: NamespaceSet{
   215  					"ns": {},
   216  				},
   217  			},
   218  			want: NamespaceSet{
   219  				"ns": {},
   220  			},
   221  		},
   222  		{
   223  			name: "MultipleLeft/MultipleRight/SomeIntersect",
   224  			in: input{
   225  				left: NamespaceSet{
   226  					"ns":   {},
   227  					"ns-1": {},
   228  					"ns-2": {},
   229  				},
   230  				right: NamespaceSet{
   231  					"ns":   {},
   232  					"ns-1": {},
   233  					"ns-3": {},
   234  				},
   235  			},
   236  			want: NamespaceSet{
   237  				"ns":   {},
   238  				"ns-1": {},
   239  			},
   240  		},
   241  		{
   242  			name: "MultipleLeft/MultipleRight/AllIntersect",
   243  			in: input{
   244  				left: NamespaceSet{
   245  					"ns":   {},
   246  					"ns-1": {},
   247  					"ns-2": {},
   248  				},
   249  				right: NamespaceSet{
   250  					"ns":   {},
   251  					"ns-1": {},
   252  					"ns-2": {},
   253  				},
   254  			},
   255  			want: NamespaceSet{
   256  				"ns":   {},
   257  				"ns-1": {},
   258  				"ns-2": {},
   259  			},
   260  		},
   261  		{
   262  			name: "AllLeft/MultipleRight/RightIsIntersection",
   263  			in: input{
   264  				left: NamespaceSet{
   265  					"": {},
   266  				},
   267  				right: NamespaceSet{
   268  					"ns":   {},
   269  					"ns-1": {},
   270  					"ns-2": {},
   271  				},
   272  			},
   273  			want: NamespaceSet{
   274  				"ns":   {},
   275  				"ns-1": {},
   276  				"ns-2": {},
   277  			},
   278  		},
   279  		{
   280  			name: "MultipleLeft/AllRight/LeftIsIntersection",
   281  			in: input{
   282  				left: NamespaceSet{
   283  					"ns":   {},
   284  					"ns-1": {},
   285  					"ns-2": {},
   286  				},
   287  				right: NamespaceSet{
   288  					"": {},
   289  				},
   290  			},
   291  			want: NamespaceSet{
   292  				"ns":   {},
   293  				"ns-1": {},
   294  				"ns-2": {},
   295  			},
   296  		},
   297  		{
   298  			name: "AllLeft/EmptyRight/NoIntersection",
   299  			in: input{
   300  				left: NamespaceSet{
   301  					"": {},
   302  				},
   303  				right: make(NamespaceSet),
   304  			},
   305  			want: make(NamespaceSet),
   306  		},
   307  		{
   308  			name: "EmptyLeft/AllRight/NoIntersection",
   309  			in: input{
   310  				left: make(NamespaceSet),
   311  				right: NamespaceSet{
   312  					"": {},
   313  				},
   314  			},
   315  			want: make(NamespaceSet),
   316  		},
   317  		{
   318  			name: "AllLeft/AllRight/Intersection",
   319  			in: input{
   320  				left: NamespaceSet{
   321  					"": {},
   322  				},
   323  				right: NamespaceSet{
   324  					"": {},
   325  				},
   326  			},
   327  			want: NamespaceSet{
   328  				"": {},
   329  			},
   330  		},
   331  	}
   332  
   333  	for _, tt := range tests {
   334  		t.Run(tt.name, func(t *testing.T) {
   335  			require.EqualValues(t, tt.want, tt.in.left.Intersection(tt.in.right))
   336  		})
   337  	}
   338  }
   339  
   340  func TestNamespaceSetUnion(t *testing.T) {
   341  	type input struct {
   342  		left  NamespaceSet
   343  		right NamespaceSet
   344  	}
   345  	tests := []struct {
   346  		name string
   347  		in   input
   348  		want NamespaceSet
   349  	}{
   350  		{
   351  			name: "EmptySets",
   352  			in: input{
   353  				left:  make(NamespaceSet),
   354  				right: make(NamespaceSet),
   355  			},
   356  			want: make(NamespaceSet),
   357  		},
   358  		{
   359  			name: "EmptyLeft/MultipleRight",
   360  			in: input{
   361  				left: make(NamespaceSet),
   362  				right: NamespaceSet{
   363  					"ns":   {},
   364  					"ns-1": {},
   365  					"ns-2": {},
   366  				},
   367  			},
   368  			want: NamespaceSet{
   369  				"ns":   {},
   370  				"ns-1": {},
   371  				"ns-2": {},
   372  			},
   373  		},
   374  		{
   375  			name: "MultipleLeft/EmptyRight",
   376  			in: input{
   377  				left: NamespaceSet{
   378  					"ns":   {},
   379  					"ns-1": {},
   380  					"ns-2": {},
   381  				},
   382  				right: make(NamespaceSet),
   383  			},
   384  			want: NamespaceSet{
   385  				"ns":   {},
   386  				"ns-1": {},
   387  				"ns-2": {},
   388  			},
   389  		},
   390  		{
   391  			name: "OneLeft/SameRight",
   392  			in: input{
   393  				left: NamespaceSet{
   394  					"ns": {},
   395  				},
   396  				right: NamespaceSet{
   397  					"ns": {},
   398  				},
   399  			},
   400  			want: NamespaceSet{
   401  				"ns": {},
   402  			},
   403  		},
   404  		{
   405  			name: "MultipleLeft/MultipleRight/Differ",
   406  			in: input{
   407  				left: NamespaceSet{
   408  					"ns":   {},
   409  					"ns-1": {},
   410  					"ns-2": {},
   411  				},
   412  				right: NamespaceSet{
   413  					"ns":   {},
   414  					"ns-1": {},
   415  					"ns-3": {},
   416  				},
   417  			},
   418  			want: NamespaceSet{
   419  				"ns":   {},
   420  				"ns-1": {},
   421  				"ns-2": {},
   422  				"ns-3": {},
   423  			},
   424  		},
   425  		{
   426  			name: "MultipleLeft/MultipleRight/AllSame",
   427  			in: input{
   428  				left: NamespaceSet{
   429  					"ns":   {},
   430  					"ns-1": {},
   431  					"ns-2": {},
   432  				},
   433  				right: NamespaceSet{
   434  					"ns":   {},
   435  					"ns-1": {},
   436  					"ns-2": {},
   437  				},
   438  			},
   439  			want: NamespaceSet{
   440  				"ns":   {},
   441  				"ns-1": {},
   442  				"ns-2": {},
   443  			},
   444  		},
   445  		{
   446  			name: "AllLeft/MultipleRight",
   447  			in: input{
   448  				left: NamespaceSet{
   449  					"": {},
   450  				},
   451  				right: NamespaceSet{
   452  					"ns":   {},
   453  					"ns-1": {},
   454  					"ns-2": {},
   455  				},
   456  			},
   457  			want: NamespaceSet{
   458  				"": {},
   459  			},
   460  		},
   461  		{
   462  			name: "MultipleLeft/AllRight",
   463  			in: input{
   464  				left: NamespaceSet{
   465  					"ns":   {},
   466  					"ns-1": {},
   467  					"ns-2": {},
   468  				},
   469  				right: NamespaceSet{
   470  					"": {},
   471  				},
   472  			},
   473  			want: NamespaceSet{
   474  				"": {},
   475  			},
   476  		},
   477  		{
   478  			name: "AllLeft/EmptyRight",
   479  			in: input{
   480  				left: NamespaceSet{
   481  					"": {},
   482  				},
   483  				right: make(NamespaceSet),
   484  			},
   485  			want: NamespaceSet{
   486  				"": {},
   487  			},
   488  		},
   489  		{
   490  			name: "EmptyLeft/AllRight",
   491  			in: input{
   492  				left: make(NamespaceSet),
   493  				right: NamespaceSet{
   494  					"": {},
   495  				},
   496  			},
   497  			want: NamespaceSet{
   498  				"": {},
   499  			},
   500  		},
   501  		{
   502  			name: "AllLeft/AllRight",
   503  			in: input{
   504  				left: NamespaceSet{
   505  					"": {},
   506  				},
   507  				right: NamespaceSet{
   508  					"": {},
   509  				},
   510  			},
   511  			want: NamespaceSet{
   512  				"": {},
   513  			},
   514  		},
   515  	}
   516  
   517  	for _, tt := range tests {
   518  		t.Run(tt.name, func(t *testing.T) {
   519  			require.EqualValues(t, tt.want, tt.in.left.Union(tt.in.right))
   520  		})
   521  	}
   522  }
   523  
   524  func TestNamespaceSetIsAllNamespaces(t *testing.T) {
   525  	type input struct {
   526  		set NamespaceSet
   527  	}
   528  	tests := []struct {
   529  		name string
   530  		in   input
   531  		want bool
   532  	}{
   533  		{
   534  			name: "All/Yes",
   535  			in: input{
   536  				set: NewNamespaceSet([]string{metav1.NamespaceAll}),
   537  			},
   538  			want: true,
   539  		},
   540  		{
   541  			name: "One/NotAll",
   542  			in: input{
   543  				set: NewNamespaceSet([]string{"a"}),
   544  			},
   545  			want: false,
   546  		},
   547  		{
   548  			name: "Many/NotAll",
   549  			in: input{
   550  				set: NewNamespaceSet([]string{"a", "b", "c"}),
   551  			},
   552  			want: false,
   553  		},
   554  	}
   555  
   556  	for _, tt := range tests {
   557  		t.Run(tt.name, func(t *testing.T) {
   558  			require.Equal(t, tt.want, tt.in.set.IsAllNamespaces())
   559  		})
   560  	}
   561  }
   562  
   563  func TestNamespaceSetContains(t *testing.T) {
   564  	type input struct {
   565  		set      NamespaceSet
   566  		contains string
   567  	}
   568  	tests := []struct {
   569  		name string
   570  		in   input
   571  		want bool
   572  	}{
   573  		{
   574  			name: "AllContainsAnything",
   575  			in: input{
   576  				set:      NewNamespaceSet([]string{metav1.NamespaceAll}),
   577  				contains: "any",
   578  			},
   579  			want: true,
   580  		},
   581  		{
   582  			name: "SetContainsChild/a",
   583  			in: input{
   584  				set:      NewNamespaceSet([]string{"a", "b"}),
   585  				contains: "a",
   586  			},
   587  			want: true,
   588  		},
   589  		{
   590  			name: "SetContainsChild/a",
   591  			in: input{
   592  				set:      NewNamespaceSet([]string{"a", "b"}),
   593  				contains: "b",
   594  			},
   595  			want: true,
   596  		},
   597  		{
   598  			name: "SetOmitsChild",
   599  			in: input{
   600  				set:      NewNamespaceSet([]string{"a", "b"}),
   601  				contains: "c",
   602  			},
   603  			want: false,
   604  		},
   605  	}
   606  
   607  	for _, tt := range tests {
   608  		t.Run(tt.name, func(t *testing.T) {
   609  			require.Equal(t, tt.want, tt.in.set.Contains(tt.in.contains))
   610  		})
   611  	}
   612  }
   613  
   614  func TestNewNamespaceSetFromString(t *testing.T) {
   615  	type input struct {
   616  		list string
   617  	}
   618  	tests := []struct {
   619  		name           string
   620  		in             input
   621  		wantNamespaces []string
   622  	}{
   623  		{
   624  			name: "SingleEntry",
   625  			in: input{
   626  				list: "a",
   627  			},
   628  			wantNamespaces: []string{"a"},
   629  		},
   630  		{
   631  			name: "TwoEntry",
   632  			in: input{
   633  				list: "a,b",
   634  			},
   635  			wantNamespaces: []string{"a", "b"},
   636  		},
   637  		{
   638  			name: "All",
   639  			in: input{
   640  				list: "",
   641  			},
   642  			wantNamespaces: []string{"a"},
   643  		},
   644  	}
   645  	for _, tt := range tests {
   646  		t.Run(tt.name, func(t *testing.T) {
   647  			for _, ns := range tt.wantNamespaces {
   648  				require.True(t, NewNamespaceSetFromString(tt.in.list).Contains(ns))
   649  			}
   650  		})
   651  	}
   652  }
   653  
   654  func buildOperatorGroup(namespace, name string, targets []string, gvks []string) *OperatorGroup {
   655  	return NewOperatorGroup(buildAPIOperatorGroup(namespace, name, targets, gvks))
   656  }
   657  
   658  func TestGroupIntersection(t *testing.T) {
   659  	type input struct {
   660  		left  OperatorGroupSurface
   661  		right []OperatorGroupSurface
   662  	}
   663  	tests := []struct {
   664  		name string
   665  		in   input
   666  		want []OperatorGroupSurface
   667  	}{
   668  		{
   669  			name: "NoTargets/NilGroups/NoIntersection",
   670  			in: input{
   671  				left:  buildOperatorGroup("ns", "empty-group", nil, nil),
   672  				right: nil,
   673  			},
   674  			want: []OperatorGroupSurface{},
   675  		},
   676  		{
   677  			name: "MatchingTarget/SingleOtherGroup/Intersection",
   678  			in: input{
   679  				left: buildOperatorGroup("ns", "group-a", []string{"ns-1"}, nil),
   680  				right: []OperatorGroupSurface{
   681  					buildOperatorGroup("ns-2", "group-b", []string{"ns-1"}, nil),
   682  				},
   683  			},
   684  			want: []OperatorGroupSurface{
   685  				buildOperatorGroup("ns-2", "group-b", []string{"ns-1"}, nil),
   686  			},
   687  		},
   688  		{
   689  			name: "TargetIsOperatorNamespace/SingleOtherGroup/Intersection",
   690  			in: input{
   691  				left: buildOperatorGroup("ns", "group-a", []string{"ns-1"}, nil),
   692  				right: []OperatorGroupSurface{
   693  					buildOperatorGroup("ns-2", "group-b", []string{"ns"}, nil),
   694  				},
   695  			},
   696  			want: []OperatorGroupSurface{
   697  				buildOperatorGroup("ns-2", "group-b", []string{"ns"}, nil),
   698  			},
   699  		},
   700  		{
   701  			name: "MatchingOperatorNamespaces/SingleOtherGroup/Intersection",
   702  			in: input{
   703  				left: buildOperatorGroup("ns", "group-a", []string{"ns-1"}, nil),
   704  				right: []OperatorGroupSurface{
   705  					buildOperatorGroup("ns", "group-b", []string{"ns-2"}, nil),
   706  				},
   707  			},
   708  			want: []OperatorGroupSurface{
   709  				buildOperatorGroup("ns", "group-b", []string{"ns-2"}, nil),
   710  			},
   711  		},
   712  		{
   713  			name: "MatchingTarget/MultipleOtherGroups/Intersection",
   714  			in: input{
   715  				left: buildOperatorGroup("ns", "group-a", []string{"ns-1"}, nil),
   716  				right: []OperatorGroupSurface{
   717  					buildOperatorGroup("ns-2", "group-b", []string{"ns-1"}, nil),
   718  					buildOperatorGroup("ns-3", "group-c", []string{"ns-1"}, nil),
   719  				},
   720  			},
   721  			want: []OperatorGroupSurface{
   722  				buildOperatorGroup("ns-2", "group-b", []string{"ns-1"}, nil),
   723  				buildOperatorGroup("ns-3", "group-c", []string{"ns-1"}, nil),
   724  			},
   725  		},
   726  		{
   727  			name: "NonMatchingTargets/MultipleOtherGroups/NoIntersection",
   728  			in: input{
   729  				left: buildOperatorGroup("ns", "group-a", []string{"ns-1", "ns-2", "ns-3"}, nil),
   730  				right: []OperatorGroupSurface{
   731  					buildOperatorGroup("ns-4", "group-b", []string{"ns-6", "ns-7", "ns-8"}, nil),
   732  					buildOperatorGroup("ns-5", "group-c", []string{"ns-6", "ns-7", "ns-8"}, nil),
   733  				},
   734  			},
   735  			want: []OperatorGroupSurface{},
   736  		},
   737  		{
   738  			name: "AllNamespaces/MultipleTargets/Intersection",
   739  			in: input{
   740  				left: buildOperatorGroup("ns", "group-a", []string{""}, nil),
   741  				right: []OperatorGroupSurface{
   742  					buildOperatorGroup("ns-4", "group-b", []string{"ns-6", "ns-7", "ns-8"}, nil),
   743  					buildOperatorGroup("ns-5", "group-c", []string{"ns-9", "ns-10", "ns-11"}, nil),
   744  					buildOperatorGroup("ns-6", "group-d", []string{"ns-11", "ns-12"}, nil),
   745  				},
   746  			},
   747  			want: []OperatorGroupSurface{
   748  				buildOperatorGroup("ns-4", "group-b", []string{"ns-6", "ns-7", "ns-8"}, nil),
   749  				buildOperatorGroup("ns-5", "group-c", []string{"ns-9", "ns-10", "ns-11"}, nil),
   750  				buildOperatorGroup("ns-6", "group-d", []string{"ns-11", "ns-12"}, nil),
   751  			},
   752  		},
   753  		{
   754  			name: "MatchingTargetAllNamespace/MultipleTargets/Intersection",
   755  			in: input{
   756  				left: buildOperatorGroup("ns", "group-a", []string{"ns-1", "ns-2", "ns-3"}, nil),
   757  				right: []OperatorGroupSurface{
   758  					buildOperatorGroup("ns-4", "group-b", []string{""}, nil),
   759  					buildOperatorGroup("ns-5", "group-c", []string{"ns-9", "ns-10", "ns-11"}, nil),
   760  					buildOperatorGroup("ns-6", "group-d", []string{"ns-11", "ns-12"}, nil),
   761  				},
   762  			},
   763  			want: []OperatorGroupSurface{
   764  				buildOperatorGroup("ns-4", "group-b", []string{""}, nil),
   765  			},
   766  		},
   767  		{
   768  			name: "AllNamespace/MultipleTargets/OneAllNamespace/Intersection",
   769  			in: input{
   770  				left: buildOperatorGroup("ns", "group-a", []string{""}, nil),
   771  				right: []OperatorGroupSurface{
   772  					buildOperatorGroup("ns-4", "group-b", []string{""}, nil),
   773  					buildOperatorGroup("ns-5", "group-c", []string{"ns-9", "ns-10", "ns-11"}, nil),
   774  					buildOperatorGroup("ns-6", "group-d", []string{"ns-11", "ns-12"}, nil),
   775  				},
   776  			},
   777  			want: []OperatorGroupSurface{
   778  				buildOperatorGroup("ns-4", "group-b", []string{""}, nil),
   779  				buildOperatorGroup("ns-5", "group-c", []string{"ns-9", "ns-10", "ns-11"}, nil),
   780  				buildOperatorGroup("ns-6", "group-d", []string{"ns-11", "ns-12"}, nil),
   781  			},
   782  		},
   783  		{
   784  			name: "AllNamespace/AllNamespace/Intersection",
   785  			in: input{
   786  				left: buildOperatorGroup("ns", "group-a", []string{""}, nil),
   787  				right: []OperatorGroupSurface{
   788  					buildOperatorGroup("ns-4", "group-b", []string{""}, nil),
   789  				},
   790  			},
   791  			want: []OperatorGroupSurface{
   792  				buildOperatorGroup("ns-4", "group-b", []string{""}, nil),
   793  			},
   794  		},
   795  	}
   796  
   797  	for _, tt := range tests {
   798  		t.Run(tt.name, func(t *testing.T) {
   799  			require.EqualValues(t, tt.want, tt.in.left.GroupIntersection(tt.in.right...))
   800  		})
   801  	}
   802  }
   803  
   804  func apiIntersectionReconcilerSuite(t *testing.T, reconciler APIIntersectionReconciler) {
   805  	tests := []struct {
   806  		name        string
   807  		add         cache.APISet
   808  		group       OperatorGroupSurface
   809  		otherGroups []OperatorGroupSurface
   810  		want        APIReconciliationResult
   811  	}{
   812  		{
   813  			name:        "Empty/NoAPIConflict",
   814  			add:         make(cache.APISet),
   815  			group:       buildOperatorGroup("ns", "g1", []string{"ns"}, nil),
   816  			otherGroups: nil,
   817  			want:        NoAPIConflict,
   818  		},
   819  		{
   820  			name: "NoNamespaceIntersection/APIIntersection/NoAPIConflict",
   821  			add: cache.APISet{
   822  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   823  			},
   824  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
   825  			otherGroups: []OperatorGroupSurface{
   826  				buildOperatorGroup("ns-2", "g1", []string{"ns-3"}, []string{"Goose.v1alpha1.birds.com"}),
   827  			},
   828  			want: NoAPIConflict,
   829  		},
   830  		{
   831  			name: "NamespaceIntersection/NoAPIIntersection/NoAPIConflict",
   832  			add: cache.APISet{
   833  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   834  			},
   835  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
   836  			otherGroups: []OperatorGroupSurface{
   837  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Moose.v1alpha1.mammals.com"}),
   838  			},
   839  			want: NoAPIConflict,
   840  		},
   841  		{
   842  			name: "MultipleNamespaceIntersections/NoAPIIntersection/NoAPIConflict",
   843  			add: cache.APISet{
   844  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   845  			},
   846  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
   847  			otherGroups: []OperatorGroupSurface{
   848  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Moose.v1alpha1.mammals.com"}),
   849  				buildOperatorGroup("ns-2", "g1", []string{"ns"}, []string{"Egret.v1alpha1.birds.com"}),
   850  			},
   851  			want: NoAPIConflict,
   852  		},
   853  		{
   854  			name: "SomeNamespaceIntersection/NoAPIIntersection/NoAPIConflict",
   855  			add: cache.APISet{
   856  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}:   {},
   857  				opregistry.APIKey{Group: "mammals.com", Version: "v1alpha1", Kind: "Moose"}: {},
   858  			},
   859  			group: buildOperatorGroup("ns", "g1", []string{"ns-1", "ns-2", "ns-3"}, []string{"Goose.v1alpha1.birds.com,Moose.v1alpha1.mammals.com"}),
   860  			otherGroups: []OperatorGroupSurface{
   861  				buildOperatorGroup("ns-7", "g1", []string{"ns-4"}, []string{"Moose.v1alpha1.mammals.com"}),
   862  				buildOperatorGroup("ns-8", "g1", []string{"ns-5"}, []string{"Goose.v1alpha1.birds.com"}),
   863  				buildOperatorGroup("ns-9", "g1", []string{""}, []string{"Goat.v1alpha1.mammals.com"}),
   864  			},
   865  			want: NoAPIConflict,
   866  		},
   867  		{
   868  			name: "AllNamespaceIntersection/NoAPIIntersection/NoAPIConflict",
   869  			add: cache.APISet{
   870  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   871  			},
   872  			group: buildOperatorGroup("ns", "g1", []string{""}, []string{"Goose.v1alpha1.birds.com"}),
   873  			otherGroups: []OperatorGroupSurface{
   874  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Moose.v1alpha1.mammals.com"}),
   875  			},
   876  			want: NoAPIConflict,
   877  		},
   878  		{
   879  			name: "AllNamespaceIntersectionOnOther/NoAPIIntersection/NoAPIConflict",
   880  			add: cache.APISet{
   881  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   882  			},
   883  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
   884  			otherGroups: []OperatorGroupSurface{
   885  				buildOperatorGroup("ns-2", "g1", []string{""}, []string{"Moose.v1alpha1.mammals.com"}),
   886  			},
   887  			want: NoAPIConflict,
   888  		},
   889  		{
   890  			name: "AllNamespaceInstersectionOnOther/NoAPIIntersection/NoAPIConflict",
   891  			add: cache.APISet{
   892  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   893  			},
   894  			group: buildOperatorGroup("ns", "g1", []string{""}, []string{"Goose.v1alpha1.birds.com"}),
   895  			otherGroups: []OperatorGroupSurface{
   896  				buildOperatorGroup("ns-2", "g1", []string{""}, []string{"Moose.v1alpha1.mammals.com"}),
   897  			},
   898  			want: NoAPIConflict,
   899  		},
   900  		{
   901  			name: "NamespaceIntersection/NoAPIIntersection/NoAPIConflict",
   902  			add: cache.APISet{
   903  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   904  			},
   905  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
   906  			otherGroups: []OperatorGroupSurface{
   907  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, nil),
   908  			},
   909  			want: NoAPIConflict,
   910  		},
   911  		{
   912  			name: "NamespaceIntersection/APIIntersection/APIConflict",
   913  			add: cache.APISet{
   914  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   915  			},
   916  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, nil),
   917  			otherGroups: []OperatorGroupSurface{
   918  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
   919  			},
   920  			want: APIConflict,
   921  		},
   922  		{
   923  			name: "AllNamespaceIntersection/APIIntersection/APIConflict",
   924  			add: cache.APISet{
   925  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   926  			},
   927  			group: buildOperatorGroup("ns", "g1", []string{""}, nil),
   928  			otherGroups: []OperatorGroupSurface{
   929  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
   930  			},
   931  			want: APIConflict,
   932  		},
   933  		{
   934  			name: "AllNamespaceIntersectionOnOther/APIIntersection/APIConflict",
   935  			add: cache.APISet{
   936  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   937  			},
   938  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, nil),
   939  			otherGroups: []OperatorGroupSurface{
   940  				buildOperatorGroup("ns-2", "g1", []string{""}, []string{"Goose.v1alpha1.birds.com"}),
   941  			},
   942  			want: APIConflict,
   943  		},
   944  		{
   945  			name: "AllNamespaceIntersectionOnBoth/APIIntersection/APIConflict",
   946  			add: cache.APISet{
   947  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   948  			},
   949  			group: buildOperatorGroup("ns", "g1", []string{""}, nil),
   950  			otherGroups: []OperatorGroupSurface{
   951  				buildOperatorGroup("ns-2", "g1", []string{""}, []string{"Goose.v1alpha1.birds.com"}),
   952  			},
   953  			want: APIConflict,
   954  		},
   955  		{
   956  			name: "NamespaceIntersection/SomeAPIIntersection/APIConflict",
   957  			add: cache.APISet{
   958  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   959  			},
   960  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, nil),
   961  			otherGroups: []OperatorGroupSurface{
   962  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Moose.v1alpha1.birds.com"}),
   963  				buildOperatorGroup("ns-3", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com,Egret.v1alpha1.birds.com"}),
   964  			},
   965  			want: APIConflict,
   966  		},
   967  		{
   968  			name: "NamespaceIntersectionOnOperatorNamespace/SomeAPIIntersection/APIConflict",
   969  			add: cache.APISet{
   970  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   971  			},
   972  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, nil),
   973  			otherGroups: []OperatorGroupSurface{
   974  				buildOperatorGroup("ns-3", "g1", []string{"ns"}, []string{"Goose.v1alpha1.birds.com,Egret.v1alpha1.birds.com"}),
   975  			},
   976  			want: APIConflict,
   977  		},
   978  
   979  		{
   980  			name: "NoNamespaceIntersection/NoAPIIntersection/AddAPIs",
   981  			add: cache.APISet{
   982  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   983  			},
   984  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, nil),
   985  			otherGroups: []OperatorGroupSurface{
   986  				buildOperatorGroup("ns-2", "g1", []string{"ns-2"}, []string{"Goose.v1alpha1.birds.com"}),
   987  			},
   988  			want: AddAPIs,
   989  		},
   990  		{
   991  			name: "NamespaceIntersection/NoAPIIntersection/AddAPIs",
   992  			add: cache.APISet{
   993  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
   994  			},
   995  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, nil),
   996  			otherGroups: []OperatorGroupSurface{
   997  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Moose.v1alpha1.mammals.com"}),
   998  			},
   999  			want: AddAPIs,
  1000  		},
  1001  		{
  1002  			name: "OperatorNamespaceIntersection/NoAPIIntersection/AddAPIs",
  1003  			add: cache.APISet{
  1004  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
  1005  			},
  1006  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, nil),
  1007  			otherGroups: []OperatorGroupSurface{
  1008  				buildOperatorGroup("ns-2", "g1", []string{"ns"}, []string{"Moose.v1alpha1.mammals.com"}),
  1009  			},
  1010  			want: AddAPIs,
  1011  		},
  1012  		{
  1013  			name: "AllNamespaceIntersection/NoAPIIntersection/AddAPIs",
  1014  			add: cache.APISet{
  1015  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
  1016  			},
  1017  			group: buildOperatorGroup("ns", "g1", []string{""}, nil),
  1018  			otherGroups: []OperatorGroupSurface{
  1019  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Moose.v1alpha1.mammals.com"}),
  1020  				buildOperatorGroup("ns-3", "g1", []string{"ns-1"}, []string{"Goat.v1alpha1.mammals.com,Egret.v1alpha1.birds.com"}),
  1021  			},
  1022  			want: AddAPIs,
  1023  		},
  1024  		{
  1025  			name: "AllNamespaceIntersectionOnOthers/NoAPIIntersection/AddAPIs",
  1026  			add: cache.APISet{
  1027  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
  1028  			},
  1029  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, nil),
  1030  			otherGroups: []OperatorGroupSurface{
  1031  				buildOperatorGroup("ns-2", "g1", []string{""}, []string{"Moose.v1alpha1.mammals.com"}),
  1032  				buildOperatorGroup("ns-3", "g1", []string{""}, []string{"Goat.v1alpha1.mammals.com,Egret.v1alpha1.birds.com"}),
  1033  			},
  1034  			want: AddAPIs,
  1035  		},
  1036  		{
  1037  			name: "AllNamespaceIntersectionOnOthers/NoAPIIntersection/AddAPIs/PrexistingAddition",
  1038  			add: cache.APISet{
  1039  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
  1040  				opregistry.APIKey{Group: "mammals.com", Version: "v1alpha1", Kind: "Cow"}: {},
  1041  			},
  1042  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, []string{"Cow.v1alpha1.mammals.com"}),
  1043  			otherGroups: []OperatorGroupSurface{
  1044  				buildOperatorGroup("ns-2", "g1", []string{""}, []string{"Moose.v1alpha1.mammals.com"}),
  1045  				buildOperatorGroup("ns-3", "g1", []string{""}, []string{"Goat.v1alpha1.mammals.com,Egret.v1alpha1.birds.com"}),
  1046  			},
  1047  			want: AddAPIs,
  1048  		},
  1049  		{
  1050  			name: "NamespaceInstersection/APIIntersection/RemoveAPIs",
  1051  			add: cache.APISet{
  1052  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
  1053  			},
  1054  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
  1055  			otherGroups: []OperatorGroupSurface{
  1056  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
  1057  			},
  1058  			want: RemoveAPIs,
  1059  		},
  1060  		{
  1061  			name: "AllNamespaceInstersection/APIIntersection/RemoveAPIs",
  1062  			add: cache.APISet{
  1063  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
  1064  			},
  1065  			group: buildOperatorGroup("ns", "g1", []string{""}, []string{"Goose.v1alpha1.birds.com"}),
  1066  			otherGroups: []OperatorGroupSurface{
  1067  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
  1068  			},
  1069  			want: RemoveAPIs,
  1070  		},
  1071  		{
  1072  			name: "AllNamespaceInstersectionOnOther/APIIntersection/RemoveAPIs",
  1073  			add: cache.APISet{
  1074  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
  1075  			},
  1076  			group: buildOperatorGroup("ns", "g1", []string{""}, []string{"Goose.v1alpha1.birds.com"}),
  1077  			otherGroups: []OperatorGroupSurface{
  1078  				buildOperatorGroup("ns-2", "g1", []string{""}, []string{"Goose.v1alpha1.birds.com"}),
  1079  			},
  1080  			want: RemoveAPIs,
  1081  		},
  1082  		{
  1083  			name: "MultipleNamespaceIntersections/APIIntersection/RemoveAPIs",
  1084  			add: cache.APISet{
  1085  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}: {},
  1086  			},
  1087  			group: buildOperatorGroup("ns", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
  1088  			otherGroups: []OperatorGroupSurface{
  1089  				buildOperatorGroup("ns-2", "g1", []string{"ns-1"}, []string{"Goose.v1alpha1.birds.com"}),
  1090  				buildOperatorGroup("ns-2", "g1", []string{"ns"}, []string{"Goose.v1alpha1.birds.com"}),
  1091  			},
  1092  			want: RemoveAPIs,
  1093  		},
  1094  		{
  1095  			name: "SomeNamespaceIntersection/APIIntersection/RemoveAPIs",
  1096  			add: cache.APISet{
  1097  				opregistry.APIKey{Group: "birds.com", Version: "v1alpha1", Kind: "Goose"}:   {},
  1098  				opregistry.APIKey{Group: "mammals.com", Version: "v1alpha1", Kind: "Moose"}: {},
  1099  			},
  1100  			group: buildOperatorGroup("ns", "g1", []string{"ns-1", "ns-2", "ns-3"}, []string{"Goose.v1alpha1.birds.com,Moose.v1alpha1.mammals.com"}),
  1101  			otherGroups: []OperatorGroupSurface{
  1102  				buildOperatorGroup("ns-7", "g1", []string{"ns-4"}, []string{"Moose.v1alpha1.mammals.com"}),
  1103  				buildOperatorGroup("ns-8", "g1", []string{"ns-5", "ns-3"}, []string{"Goose.v1alpha1.birds.com"}),
  1104  				buildOperatorGroup("ns-9", "g1", []string{""}, []string{"Goat.v1alpha1.mammals.com"}),
  1105  			},
  1106  			want: RemoveAPIs,
  1107  		},
  1108  	}
  1109  
  1110  	for _, tt := range tests {
  1111  		t.Run(tt.name, func(t *testing.T) {
  1112  			require.Equal(t, tt.want, reconciler.Reconcile(tt.add, tt.group, tt.otherGroups...))
  1113  		})
  1114  	}
  1115  }
  1116  func TestReconcileAPIIntersection(t *testing.T) {
  1117  	apiIntersectionReconcilerSuite(t, APIIntersectionReconcileFunc(ReconcileAPIIntersection))
  1118  }