github.com/argoproj/argo-cd/v2@v2.10.9/controller/sharding/cache_test.go (about)

     1  package sharding
     2  
     3  import (
     4  	"testing"
     5  
     6  	"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
     7  	dbmocks "github.com/argoproj/argo-cd/v2/util/db/mocks"
     8  	"github.com/stretchr/testify/assert"
     9  )
    10  
    11  func setupTestSharding(shard int, replicas int) *ClusterSharding {
    12  	shardingAlgorithm := "legacy" // we are using the legacy algorithm as it is deterministic based on the cluster id which is easier to test
    13  	db := &dbmocks.ArgoDB{}
    14  	return NewClusterSharding(db, shard, replicas, shardingAlgorithm).(*ClusterSharding)
    15  }
    16  
    17  func TestNewClusterSharding(t *testing.T) {
    18  	shard := 1
    19  	replicas := 2
    20  	sharding := setupTestSharding(shard, replicas)
    21  
    22  	assert.NotNil(t, sharding)
    23  	assert.Equal(t, shard, sharding.Shard)
    24  	assert.Equal(t, replicas, sharding.Replicas)
    25  	assert.NotNil(t, sharding.Shards)
    26  	assert.NotNil(t, sharding.Clusters)
    27  }
    28  
    29  func TestClusterSharding_Add(t *testing.T) {
    30  	shard := 1
    31  	replicas := 2
    32  	sharding := setupTestSharding(shard, replicas)
    33  
    34  	clusterA := &v1alpha1.Cluster{
    35  		ID:     "2",
    36  		Server: "https://127.0.0.1:6443",
    37  	}
    38  
    39  	sharding.Add(clusterA)
    40  
    41  	clusterB := v1alpha1.Cluster{
    42  		ID:     "1",
    43  		Server: "https://kubernetes.default.svc",
    44  	}
    45  
    46  	sharding.Add(&clusterB)
    47  
    48  	distribution := sharding.GetDistribution()
    49  
    50  	assert.Contains(t, sharding.Clusters, clusterA.Server)
    51  	assert.Contains(t, sharding.Clusters, clusterB.Server)
    52  
    53  	clusterDistribution, ok := distribution[clusterA.Server]
    54  	assert.True(t, ok)
    55  	assert.Equal(t, 1, clusterDistribution)
    56  
    57  	myClusterDistribution, ok := distribution[clusterB.Server]
    58  	assert.True(t, ok)
    59  	assert.Equal(t, 0, myClusterDistribution)
    60  
    61  	assert.Equal(t, 2, len(distribution))
    62  }
    63  
    64  func TestClusterSharding_AddRoundRobin_Redistributes(t *testing.T) {
    65  	shard := 1
    66  	replicas := 2
    67  
    68  	db := &dbmocks.ArgoDB{}
    69  
    70  	sharding := NewClusterSharding(db, shard, replicas, "round-robin").(*ClusterSharding)
    71  
    72  	clusterA := &v1alpha1.Cluster{
    73  		ID:     "1",
    74  		Server: "https://127.0.0.1:6443",
    75  	}
    76  	sharding.Add(clusterA)
    77  
    78  	clusterB := v1alpha1.Cluster{
    79  		ID:     "3",
    80  		Server: "https://kubernetes.default.svc",
    81  	}
    82  	sharding.Add(&clusterB)
    83  
    84  	distributionBefore := sharding.GetDistribution()
    85  
    86  	assert.Contains(t, sharding.Clusters, clusterA.Server)
    87  	assert.Contains(t, sharding.Clusters, clusterB.Server)
    88  
    89  	clusterDistributionA, ok := distributionBefore[clusterA.Server]
    90  	assert.True(t, ok)
    91  	assert.Equal(t, 0, clusterDistributionA)
    92  
    93  	clusterDistributionB, ok := distributionBefore[clusterB.Server]
    94  	assert.True(t, ok)
    95  	assert.Equal(t, 1, clusterDistributionB)
    96  
    97  	assert.Equal(t, 2, len(distributionBefore))
    98  
    99  	clusterC := v1alpha1.Cluster{
   100  		ID:     "2",
   101  		Server: "https://1.1.1.1",
   102  	}
   103  	sharding.Add(&clusterC)
   104  
   105  	distributionAfter := sharding.GetDistribution()
   106  
   107  	assert.Contains(t, sharding.Clusters, clusterA.Server)
   108  	assert.Contains(t, sharding.Clusters, clusterB.Server)
   109  	assert.Contains(t, sharding.Clusters, clusterC.Server)
   110  
   111  	clusterDistributionA, ok = distributionAfter[clusterA.Server]
   112  	assert.True(t, ok)
   113  	assert.Equal(t, 0, clusterDistributionA)
   114  
   115  	clusterDistributionC, ok := distributionAfter[clusterC.Server]
   116  	assert.True(t, ok)
   117  	assert.Equal(t, 1, clusterDistributionC) // will be assigned to shard 1 because the .ID is smaller then the "B" cluster
   118  
   119  	clusterDistributionB, ok = distributionAfter[clusterB.Server]
   120  	assert.True(t, ok)
   121  	assert.Equal(t, 0, clusterDistributionB) // will be reassigned to shard 0 because the .ID is bigger then the "C" cluster
   122  }
   123  
   124  func TestClusterSharding_Delete(t *testing.T) {
   125  	shard := 1
   126  	replicas := 2
   127  	sharding := setupTestSharding(shard, replicas)
   128  
   129  	sharding.Init(
   130  		&v1alpha1.ClusterList{
   131  			Items: []v1alpha1.Cluster{
   132  				{
   133  					ID:     "2",
   134  					Server: "https://127.0.0.1:6443",
   135  				},
   136  				{
   137  					ID:     "1",
   138  					Server: "https://kubernetes.default.svc",
   139  				},
   140  			},
   141  		},
   142  	)
   143  
   144  	sharding.Delete("https://kubernetes.default.svc")
   145  	distribution := sharding.GetDistribution()
   146  	assert.Equal(t, 1, len(distribution))
   147  }
   148  
   149  func TestClusterSharding_Update(t *testing.T) {
   150  	shard := 1
   151  	replicas := 2
   152  	sharding := setupTestSharding(shard, replicas)
   153  
   154  	sharding.Init(
   155  		&v1alpha1.ClusterList{
   156  			Items: []v1alpha1.Cluster{
   157  				{
   158  					ID:     "2",
   159  					Server: "https://127.0.0.1:6443",
   160  				},
   161  				{
   162  					ID:     "1",
   163  					Server: "https://kubernetes.default.svc",
   164  				},
   165  			},
   166  		},
   167  	)
   168  
   169  	distributionBefore := sharding.GetDistribution()
   170  	assert.Equal(t, 2, len(distributionBefore))
   171  
   172  	distributionA, ok := distributionBefore["https://kubernetes.default.svc"]
   173  	assert.True(t, ok)
   174  	assert.Equal(t, 0, distributionA)
   175  
   176  	sharding.Update(&v1alpha1.Cluster{
   177  		ID:     "1",
   178  		Server: "https://kubernetes.default.svc",
   179  	}, &v1alpha1.Cluster{
   180  		ID:     "4",
   181  		Server: "https://kubernetes.default.svc",
   182  	})
   183  
   184  	distributionAfter := sharding.GetDistribution()
   185  	assert.Equal(t, 2, len(distributionAfter))
   186  
   187  	distributionA, ok = distributionAfter["https://kubernetes.default.svc"]
   188  	assert.True(t, ok)
   189  	assert.Equal(t, 1, distributionA)
   190  }
   191  
   192  func TestClusterSharding_UpdateServerName(t *testing.T) {
   193  	shard := 1
   194  	replicas := 2
   195  	sharding := setupTestSharding(shard, replicas)
   196  
   197  	sharding.Init(
   198  		&v1alpha1.ClusterList{
   199  			Items: []v1alpha1.Cluster{
   200  				{
   201  					ID:     "2",
   202  					Server: "https://127.0.0.1:6443",
   203  				},
   204  				{
   205  					ID:     "1",
   206  					Server: "https://kubernetes.default.svc",
   207  				},
   208  			},
   209  		},
   210  	)
   211  
   212  	distributionBefore := sharding.GetDistribution()
   213  	assert.Equal(t, 2, len(distributionBefore))
   214  
   215  	distributionA, ok := distributionBefore["https://kubernetes.default.svc"]
   216  	assert.True(t, ok)
   217  	assert.Equal(t, 0, distributionA)
   218  
   219  	sharding.Update(&v1alpha1.Cluster{
   220  		ID:     "1",
   221  		Server: "https://kubernetes.default.svc",
   222  	}, &v1alpha1.Cluster{
   223  		ID:     "1",
   224  		Server: "https://server2",
   225  	})
   226  
   227  	distributionAfter := sharding.GetDistribution()
   228  	assert.Equal(t, 2, len(distributionAfter))
   229  
   230  	_, ok = distributionAfter["https://kubernetes.default.svc"]
   231  	assert.False(t, ok) // the old server name should not be present anymore
   232  
   233  	_, ok = distributionAfter["https://server2"]
   234  	assert.True(t, ok) // the new server name should be present
   235  }
   236  
   237  func TestClusterSharding_IsManagedCluster(t *testing.T) {
   238  	replicas := 2
   239  	sharding0 := setupTestSharding(0, replicas)
   240  
   241  	sharding0.Init(
   242  		&v1alpha1.ClusterList{
   243  			Items: []v1alpha1.Cluster{
   244  				{
   245  					ID:     "1",
   246  					Server: "https://kubernetes.default.svc",
   247  				},
   248  				{
   249  					ID:     "2",
   250  					Server: "https://127.0.0.1:6443",
   251  				},
   252  			},
   253  		},
   254  	)
   255  
   256  	assert.True(t, sharding0.IsManagedCluster(&v1alpha1.Cluster{
   257  		ID:     "1",
   258  		Server: "https://kubernetes.default.svc",
   259  	}))
   260  
   261  	assert.False(t, sharding0.IsManagedCluster(&v1alpha1.Cluster{
   262  		ID:     "2",
   263  		Server: "https://127.0.0.1:6443",
   264  	}))
   265  
   266  	sharding1 := setupTestSharding(1, replicas)
   267  
   268  	sharding1.Init(
   269  		&v1alpha1.ClusterList{
   270  			Items: []v1alpha1.Cluster{
   271  				{
   272  					ID:     "2",
   273  					Server: "https://127.0.0.1:6443",
   274  				},
   275  				{
   276  					ID:     "1",
   277  					Server: "https://kubernetes.default.svc",
   278  				},
   279  			},
   280  		},
   281  	)
   282  
   283  	assert.False(t, sharding1.IsManagedCluster(&v1alpha1.Cluster{
   284  		ID:     "1",
   285  		Server: "https://kubernetes.default.svc",
   286  	}))
   287  
   288  	assert.True(t, sharding1.IsManagedCluster(&v1alpha1.Cluster{
   289  		ID:     "2",
   290  		Server: "https://127.0.0.1:6443",
   291  	}))
   292  
   293  }
   294  
   295  func TestClusterSharding_ClusterShardOfResourceShouldNotBeChanged(t *testing.T) {
   296  	shard := 1
   297  	replicas := 2
   298  	sharding := setupTestSharding(shard, replicas)
   299  
   300  	Int64Ptr := func(i int64) *int64 {
   301  		return &i
   302  	}
   303  
   304  	clusterWithNil := &v1alpha1.Cluster{
   305  		ID:     "2",
   306  		Server: "https://127.0.0.1:6443",
   307  		Shard:  nil,
   308  	}
   309  
   310  	clusterWithValue := &v1alpha1.Cluster{
   311  		ID:     "1",
   312  		Server: "https://kubernetes.default.svc",
   313  		Shard:  Int64Ptr(1),
   314  	}
   315  
   316  	clusterWithToBigValue := &v1alpha1.Cluster{
   317  		ID:     "3",
   318  		Server: "https://1.1.1.1",
   319  		Shard:  Int64Ptr(999), // shard value is explicitly bigger than the number of replicas
   320  	}
   321  
   322  	sharding.Init(
   323  		&v1alpha1.ClusterList{
   324  			Items: []v1alpha1.Cluster{
   325  				*clusterWithNil,
   326  				*clusterWithValue,
   327  				*clusterWithToBigValue,
   328  			},
   329  		},
   330  	)
   331  	distribution := sharding.GetDistribution()
   332  	assert.Equal(t, 3, len(distribution))
   333  
   334  	assert.Nil(t, sharding.Clusters[clusterWithNil.Server].Shard)
   335  
   336  	assert.NotNil(t, sharding.Clusters[clusterWithValue.Server].Shard)
   337  	assert.Equal(t, int64(1), *sharding.Clusters[clusterWithValue.Server].Shard)
   338  	assert.Equal(t, 1, distribution[clusterWithValue.Server])
   339  
   340  	assert.NotNil(t, sharding.Clusters[clusterWithToBigValue.Server].Shard)
   341  	assert.Equal(t, int64(999), *sharding.Clusters[clusterWithToBigValue.Server].Shard)
   342  	assert.Equal(t, 0, distribution[clusterWithToBigValue.Server]) // will be assigned to shard 0 because the value is bigger than the number of replicas
   343  }
   344  
   345  func TestHasShardingUpdates(t *testing.T) {
   346  	Int64Ptr := func(i int64) *int64 {
   347  		return &i
   348  	}
   349  
   350  	testCases := []struct {
   351  		name     string
   352  		old      *v1alpha1.Cluster
   353  		new      *v1alpha1.Cluster
   354  		expected bool
   355  	}{
   356  		{
   357  			name: "No updates",
   358  			old: &v1alpha1.Cluster{
   359  				Server: "https://kubernetes.default.svc",
   360  				Shard:  Int64Ptr(1),
   361  			},
   362  			new: &v1alpha1.Cluster{
   363  				Server: "https://kubernetes.default.svc",
   364  				Shard:  Int64Ptr(1),
   365  			},
   366  			expected: false,
   367  		},
   368  		{
   369  			name: "Updates",
   370  			old: &v1alpha1.Cluster{
   371  				Server: "https://kubernetes.default.svc",
   372  				Shard:  Int64Ptr(1),
   373  			},
   374  			new: &v1alpha1.Cluster{
   375  				Server: "https://kubernetes.default.svc",
   376  				Shard:  Int64Ptr(2),
   377  			},
   378  			expected: true,
   379  		},
   380  		{
   381  			name: "Old is nil",
   382  			old:  nil,
   383  			new: &v1alpha1.Cluster{
   384  				Server: "https://kubernetes.default.svc",
   385  				Shard:  Int64Ptr(2),
   386  			},
   387  			expected: false,
   388  		},
   389  		{
   390  			name: "New is nil",
   391  			old: &v1alpha1.Cluster{
   392  				Server: "https://kubernetes.default.svc",
   393  				Shard:  Int64Ptr(2),
   394  			},
   395  			new:      nil,
   396  			expected: false,
   397  		},
   398  		{
   399  			name:     "Both are nil",
   400  			old:      nil,
   401  			new:      nil,
   402  			expected: false,
   403  		},
   404  		{
   405  			name: "Both shards are nil",
   406  			old: &v1alpha1.Cluster{
   407  				Server: "https://kubernetes.default.svc",
   408  				Shard:  nil,
   409  			},
   410  			new: &v1alpha1.Cluster{
   411  				Server: "https://kubernetes.default.svc",
   412  				Shard:  nil,
   413  			},
   414  			expected: false,
   415  		},
   416  		{
   417  			name: "Old shard is nil",
   418  			old: &v1alpha1.Cluster{
   419  				Server: "https://kubernetes.default.svc",
   420  				Shard:  nil,
   421  			},
   422  			new: &v1alpha1.Cluster{
   423  				Server: "https://kubernetes.default.svc",
   424  				Shard:  Int64Ptr(2),
   425  			},
   426  			expected: true,
   427  		},
   428  		{
   429  			name: "New shard is nil",
   430  			old: &v1alpha1.Cluster{
   431  				Server: "https://kubernetes.default.svc",
   432  				Shard:  Int64Ptr(2),
   433  			},
   434  			new: &v1alpha1.Cluster{
   435  				Server: "https://kubernetes.default.svc",
   436  				Shard:  nil,
   437  			},
   438  			expected: true,
   439  		},
   440  		{
   441  			name: "Cluster ID has changed",
   442  			old: &v1alpha1.Cluster{
   443  				ID:     "1",
   444  				Server: "https://kubernetes.default.svc",
   445  				Shard:  Int64Ptr(2),
   446  			},
   447  			new: &v1alpha1.Cluster{
   448  				ID:     "2",
   449  				Server: "https://kubernetes.default.svc",
   450  				Shard:  Int64Ptr(2),
   451  			},
   452  			expected: true,
   453  		},
   454  		{
   455  			name: "Server has changed",
   456  			old: &v1alpha1.Cluster{
   457  				ID:     "1",
   458  				Server: "https://server1",
   459  				Shard:  Int64Ptr(2),
   460  			},
   461  			new: &v1alpha1.Cluster{
   462  				ID:     "1",
   463  				Server: "https://server2",
   464  				Shard:  Int64Ptr(2),
   465  			},
   466  			expected: true,
   467  		},
   468  	}
   469  
   470  	for _, tc := range testCases {
   471  		t.Run(tc.name, func(t *testing.T) {
   472  			assert.Equal(t, tc.expected, hasShardingUpdates(tc.old, tc.new))
   473  		})
   474  	}
   475  }