@@ -1320,282 +1320,6 @@ func TestSyncerProcessingSingleResourceWithStatus(t *testing.T) {
1320
1320
})
1321
1321
}
1322
1322
}
1323
- func TestSyncerProcessingRelatedResources (t * testing.T ) {
1324
- type testcase struct {
1325
- name string
1326
- remoteAPIGroup string
1327
- localCRD * apiextensionsv1.CustomResourceDefinition
1328
- pubRes * syncagentv1alpha1.PublishedResource
1329
- remoteObject * unstructured.Unstructured
1330
- localObject * unstructured.Unstructured
1331
- existingState string
1332
- performRequeues bool
1333
- expectedRemoteObject * unstructured.Unstructured
1334
- expectedLocalObject * unstructured.Unstructured
1335
- expectedState string
1336
- customVerification func (t * testing.T , requeue bool , processErr error , finalRemoteObject * unstructured.Unstructured , finalLocalObject * unstructured.Unstructured , testcase testcase )
1337
- }
1338
-
1339
- clusterName := logicalcluster .Name ("testcluster" )
1340
-
1341
- remoteThingPR := & syncagentv1alpha1.PublishedResource {
1342
- Spec : syncagentv1alpha1.PublishedResourceSpec {
1343
- Resource : syncagentv1alpha1.SourceResourceDescriptor {
1344
- APIGroup : dummyv1alpha1 .GroupName ,
1345
- Version : dummyv1alpha1 .GroupVersion ,
1346
- Kind : "Thing" ,
1347
- },
1348
- Projection : & syncagentv1alpha1.ResourceProjection {
1349
- Kind : "RemoteThing" ,
1350
- },
1351
- // include explicit naming rules to be independent of possible changes to the defaults
1352
- Naming : & syncagentv1alpha1.ResourceNaming {
1353
- Name : "$remoteClusterName-$remoteName" , // Things are Cluster-scoped
1354
- },
1355
- Related : []syncagentv1alpha1.RelatedResourceSpec {
1356
- {
1357
- Identifier : "mandatory-secret" ,
1358
- Origin : "service" ,
1359
- Kind : "Thing" ,
1360
- Reference : syncagentv1alpha1.RelatedResourceReference {
1361
- Name : syncagentv1alpha1.ResourceLocator {
1362
- Path : "spec.otherTest.name" ,
1363
- },
1364
- Namespace : & syncagentv1alpha1.ResourceLocator {
1365
- Path : "spec.otherTest.namespace" ,
1366
- },
1367
- },
1368
- Optional : false ,
1369
- },
1370
- {
1371
- Identifier : "optional-secret" ,
1372
- Origin : "kcp" ,
1373
- Kind : "Thing" ,
1374
- Reference : syncagentv1alpha1.RelatedResourceReference {
1375
- Name : syncagentv1alpha1.ResourceLocator {
1376
- Path : "spec.test.name" ,
1377
- },
1378
- Namespace : & syncagentv1alpha1.ResourceLocator {
1379
- Path : "spec.test.namespace" ,
1380
- },
1381
- },
1382
- Optional : true ,
1383
- },
1384
- },
1385
- },
1386
- }
1387
-
1388
- testcases := []testcase {
1389
- {
1390
- name : "optional related resource does not exist" ,
1391
- remoteAPIGroup : "remote.example.corp" ,
1392
- localCRD : loadCRD ("things" ),
1393
- pubRes : remoteThingPR ,
1394
- performRequeues : true ,
1395
-
1396
- remoteObject : newUnstructured (& dummyv1alpha1.Thing {
1397
- ObjectMeta : metav1.ObjectMeta {
1398
- Name : "my-test-thing" ,
1399
- },
1400
- Spec : dummyv1alpha1.ThingSpec {
1401
- Username : "Colonel Mustard" ,
1402
- },
1403
- }, withGroupKind ("remote.example.corp" , "RemoteThing" )),
1404
- localObject : nil ,
1405
- existingState : "" ,
1406
-
1407
- expectedRemoteObject : newUnstructured (& dummyv1alpha1.Thing {
1408
- ObjectMeta : metav1.ObjectMeta {
1409
- Name : "my-test-thing" ,
1410
- Finalizers : []string {
1411
- deletionFinalizer ,
1412
- },
1413
- },
1414
- Spec : dummyv1alpha1.ThingSpec {
1415
- Username : "Colonel Mustard" ,
1416
- },
1417
- }, withGroupKind ("remote.example.corp" , "RemoteThing" )),
1418
- expectedLocalObject : newUnstructured (& dummyv1alpha1.Thing {
1419
- ObjectMeta : metav1.ObjectMeta {
1420
- Name : "testcluster-my-test-thing" ,
1421
- Labels : map [string ]string {
1422
- agentNameLabel : "textor-the-doctor" ,
1423
- remoteObjectClusterLabel : "testcluster" ,
1424
- remoteObjectNameHashLabel : "c346c8ceb5d104cc783d09b95e8ea7032c190948" ,
1425
- },
1426
- Annotations : map [string ]string {
1427
- remoteObjectNameAnnotation : "my-test-thing" ,
1428
- },
1429
- },
1430
- Spec : dummyv1alpha1.ThingSpec {
1431
- Username : "Colonel Mustard" ,
1432
- },
1433
- }),
1434
- expectedState : `{"apiVersion":"remote.example.corp/v1alpha1","kind":"RemoteThing","metadata":{"name":"my-test-thing"},"spec":{"username":"Colonel Mustard"}}` ,
1435
- },
1436
- {
1437
- name : "mandatory related resource does not exist" ,
1438
- remoteAPIGroup : "remote.example.corp" ,
1439
- localCRD : loadCRD ("things" ),
1440
- pubRes : remoteThingPR ,
1441
- performRequeues : true ,
1442
-
1443
- remoteObject : newUnstructured (& dummyv1alpha1.Thing {
1444
- ObjectMeta : metav1.ObjectMeta {
1445
- Name : "my-test-thing" ,
1446
- },
1447
- Spec : dummyv1alpha1.ThingSpec {
1448
- Username : "Colonel Mustard" ,
1449
- },
1450
- }, withGroupKind ("remote.example.corp" , "RemoteThing" )),
1451
- localObject : nil ,
1452
- existingState : "" ,
1453
-
1454
- expectedRemoteObject : newUnstructured (& dummyv1alpha1.Thing {
1455
- ObjectMeta : metav1.ObjectMeta {
1456
- Name : "my-test-thing" ,
1457
- Finalizers : []string {
1458
- deletionFinalizer ,
1459
- },
1460
- },
1461
- Spec : dummyv1alpha1.ThingSpec {
1462
- Username : "Colonel Mustard" ,
1463
- },
1464
- }, withGroupKind ("remote.example.corp" , "RemoteThing" )),
1465
- expectedLocalObject : newUnstructured (& dummyv1alpha1.Thing {
1466
- ObjectMeta : metav1.ObjectMeta {
1467
- Name : "testcluster-my-test-thing" ,
1468
- Labels : map [string ]string {
1469
- agentNameLabel : "textor-the-doctor" ,
1470
- remoteObjectClusterLabel : "testcluster" ,
1471
- remoteObjectNameHashLabel : "c346c8ceb5d104cc783d09b95e8ea7032c190948" ,
1472
- },
1473
- Annotations : map [string ]string {
1474
- remoteObjectNameAnnotation : "my-test-thing" ,
1475
- },
1476
- },
1477
- Spec : dummyv1alpha1.ThingSpec {
1478
- Username : "Colonel Mustard" ,
1479
- },
1480
- }),
1481
- expectedState : `{"apiVersion":"remote.example.corp/v1alpha1","kind":"RemoteThing","metadata":{"name":"my-test-thing"},"spec":{"username":"Colonel Mustard"}}` ,
1482
- },
1483
- }
1484
-
1485
- const stateNamespace = "kcp-system"
1486
-
1487
- for _ , testcase := range testcases {
1488
- t .Run (testcase .name , func (t * testing.T ) {
1489
- localClient := buildFakeClient (testcase .localObject )
1490
- remoteClient := buildFakeClient (testcase .remoteObject )
1491
-
1492
- syncer , err := NewResourceSyncer (
1493
- // zap.Must(zap.NewDevelopment()).Sugar(),
1494
- zap .NewNop ().Sugar (),
1495
- localClient ,
1496
- remoteClient ,
1497
- testcase .pubRes ,
1498
- testcase .localCRD ,
1499
- testcase .remoteAPIGroup ,
1500
- nil ,
1501
- stateNamespace ,
1502
- "textor-the-doctor" ,
1503
- )
1504
- if err != nil {
1505
- t .Fatalf ("Failed to create syncer: %v" , err )
1506
- }
1507
-
1508
- localCtx := context .Background ()
1509
- remoteCtx := kontext .WithCluster (localCtx , clusterName )
1510
- ctx := NewContext (localCtx , remoteCtx )
1511
-
1512
- // setup a custom state backend that we can prime
1513
- var backend * kubernetesBackend
1514
- syncer .newObjectStateStore = func (primaryObject , stateCluster syncSide ) ObjectStateStore {
1515
- // .Process() is called multiple times, but we want the state to persist between reconciles.
1516
- if backend == nil {
1517
- backend = newKubernetesBackend (stateNamespace , primaryObject , stateCluster )
1518
- if testcase .existingState != "" {
1519
- if err := backend .Put (testcase .remoteObject , clusterName , []byte (testcase .existingState )); err != nil {
1520
- t .Fatalf ("Failed to prime state store: %v" , err )
1521
- }
1522
- }
1523
- }
1524
-
1525
- return & objectStateStore {
1526
- backend : backend ,
1527
- }
1528
- }
1529
-
1530
- var requeue bool
1531
-
1532
- if testcase .performRequeues {
1533
- target := testcase .remoteObject .DeepCopy ()
1534
-
1535
- for i := 0 ; true ; i ++ {
1536
- if i > 20 {
1537
- t .Fatalf ("Detected potential infinite loop, stopping after %d requeues." , i )
1538
- }
1539
-
1540
- requeue , err = syncer .Process (ctx , target )
1541
- if err != nil {
1542
- break
1543
- }
1544
-
1545
- if ! requeue {
1546
- break
1547
- }
1548
-
1549
- if err = remoteClient .Get (remoteCtx , ctrlruntimeclient .ObjectKeyFromObject (target ), target ); err != nil {
1550
- // it's possible for the processing to have deleted the remote object,
1551
- // so a NotFound is valid here
1552
- if apierrors .IsNotFound (err ) {
1553
- break
1554
- }
1555
-
1556
- t .Fatalf ("Failed to get updated remote object: %v" , err )
1557
- }
1558
- }
1559
- } else {
1560
- requeue , err = syncer .Process (ctx , testcase .remoteObject )
1561
- }
1562
-
1563
- finalRemoteObject , getErr := getFinalObjectVersion (remoteCtx , remoteClient , testcase .remoteObject , testcase .expectedRemoteObject )
1564
- if getErr != nil {
1565
- t .Fatalf ("Failed to get final remote object: %v" , getErr )
1566
- }
1567
-
1568
- finalLocalObject , getErr := getFinalObjectVersion (localCtx , localClient , testcase .localObject , testcase .expectedLocalObject )
1569
- if getErr != nil {
1570
- t .Fatalf ("Failed to get final local object: %v" , getErr )
1571
- }
1572
-
1573
- if testcase .customVerification != nil {
1574
- testcase .customVerification (t , requeue , err , finalRemoteObject , finalLocalObject , testcase )
1575
- } else {
1576
- if err != nil {
1577
- t .Fatalf ("Processing failed: %v" , err )
1578
- }
1579
-
1580
- assertObjectsEqual (t , "local" , testcase .expectedLocalObject , finalLocalObject )
1581
- assertObjectsEqual (t , "remote" , testcase .expectedRemoteObject , finalRemoteObject )
1582
-
1583
- if testcase .expectedState != "" {
1584
- if backend == nil {
1585
- t .Fatal ("Cannot check object state, state store was never instantiated." )
1586
- }
1587
-
1588
- finalState , err := backend .Get (testcase .expectedRemoteObject , clusterName )
1589
- if err != nil {
1590
- t .Fatalf ("Failed to get final state: %v" , err )
1591
- } else if ! bytes .Equal (finalState , []byte (testcase .expectedState )) {
1592
- t .Fatalf ("States do not match:\n %s" , diff .StringDiff (testcase .expectedState , string (finalState )))
1593
- }
1594
- }
1595
- }
1596
- })
1597
- }
1598
- }
1599
1323
1600
1324
func assertObjectsEqual (t * testing.T , kind string , expected , actual * unstructured.Unstructured ) {
1601
1325
if expected == nil {
0 commit comments