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 }