github.com/pingcap/tiflow@v0.0.0-20240520035814-5bf52d54e205/pkg/causality/internal/node_test.go (about) 1 // Copyright 2022 PingCAP, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 package internal 15 16 import ( 17 "testing" 18 19 "github.com/stretchr/testify/require" 20 ) 21 22 func newNodeForTest(hashes ...uint64) *Node { 23 return &Node{ 24 id: genNextNodeID(), 25 sortedDedupKeysHash: sortAndDedupHashes(hashes, 8), 26 assignedTo: unassigned, 27 RandCacheID: func() cacheID { return 100 }, 28 OnNotified: func(callback func()) { 29 // run the callback immediately 30 callback() 31 }, 32 } 33 } 34 35 func TestNodeEquals(t *testing.T) { 36 t.Parallel() 37 38 nodeA := newNodeForTest() 39 nodeB := newNodeForTest() 40 require.False(t, nodeA.nodeID() == nodeB.nodeID()) 41 require.True(t, nodeA.nodeID() == nodeA.nodeID()) 42 } 43 44 func TestNodeDependOn(t *testing.T) { 45 t.Parallel() 46 47 // Construct a dependency graph: A --> B 48 nodeA := newNodeForTest() 49 nodeB := newNodeForTest() 50 51 nodeA.dependOn(map[int64]*Node{nodeB.nodeID(): nodeB}) 52 require.Equal(t, nodeA.dependerCount(), 0) 53 require.Equal(t, nodeB.dependerCount(), 1) 54 } 55 56 func TestNodeSingleDependency(t *testing.T) { 57 t.Parallel() 58 59 // Node B depends on A 60 nodeA := newNodeForTest() 61 nodeB := newNodeForTest() 62 nodeB.dependOn(map[int64]*Node{nodeA.nodeID(): nodeA}) 63 require.True(t, nodeA.tryAssignTo(1)) 64 require.Equal(t, cacheID(1), nodeA.assignedWorkerID()) 65 require.Equal(t, cacheID(1), nodeB.assignedWorkerID()) 66 67 // Node D depends on C 68 nodeC := newNodeForTest() 69 nodeD := newNodeForTest() 70 nodeD.dependOn(map[int64]*Node{nodeA.nodeID(): nodeC}) 71 require.True(t, nodeC.tryAssignTo(2)) 72 require.Equal(t, cacheID(2), nodeC.assignedWorkerID()) 73 nodeC.remove() 74 require.Equal(t, cacheID(2), nodeD.assignedWorkerID()) 75 } 76 77 func TestNodeMultipleDependencies(t *testing.T) { 78 t.Parallel() 79 80 // Construct a dependency graph: 81 // ┌────►A 82 // C─┤ 83 // └────►B 84 85 nodeA := newNodeForTest() 86 nodeB := newNodeForTest() 87 nodeC := newNodeForTest() 88 89 nodeC.dependOn(map[int64]*Node{nodeA.nodeID(): nodeA, nodeB.nodeID(): nodeB}) 90 91 require.True(t, nodeA.tryAssignTo(1)) 92 require.True(t, nodeB.tryAssignTo(2)) 93 94 require.Equal(t, unassigned, nodeC.assignedWorkerID()) 95 96 nodeA.remove() 97 nodeB.remove() 98 require.Equal(t, int64(100), nodeC.assignedWorkerID()) 99 } 100 101 func TestNodeResolveImmediately(t *testing.T) { 102 t.Parallel() 103 104 // Node A depends on 0 unresolved dependencies and some resolved dependencies. 105 nodeA := newNodeForTest() 106 nodeA.dependOn(nil) 107 require.Equal(t, cacheID(100), nodeA.assignedWorkerID()) 108 109 // Node D depends on B and C, all of them are assigned to 1. 110 nodeB := newNodeForTest() 111 require.True(t, nodeB.tryAssignTo(1)) 112 nodeC := newNodeForTest() 113 require.True(t, nodeC.tryAssignTo(1)) 114 nodeD := newNodeForTest() 115 nodeD.dependOn(map[int64]*Node{nodeB.nodeID(): nodeB, nodeC.nodeID(): nodeC}) 116 require.Equal(t, cacheID(1), nodeD.assignedWorkerID()) 117 118 // Node E depends on B and C and some other resolved dependencies. 119 nodeB.remove() 120 nodeC.remove() 121 nodeE := newNodeForTest() 122 nodeE.dependOn(map[int64]*Node{nodeB.nodeID(): nodeB, nodeC.nodeID(): nodeC}) 123 require.Equal(t, cacheID(100), nodeE.assignedWorkerID()) 124 } 125 126 func TestNodeDependOnSelf(t *testing.T) { 127 t.Parallel() 128 129 nodeA := newNodeForTest() 130 require.Panics(t, func() { 131 nodeA.dependOn(map[int64]*Node{nodeA.nodeID(): nodeA}) 132 }) 133 } 134 135 func TestNodeDoubleAssigning(t *testing.T) { 136 t.Parallel() 137 138 nodeA := newNodeForTest() 139 nodeA.TrySendToTxnCache = func(id cacheID) bool { 140 return id == 2 141 } 142 require.False(t, nodeA.tryAssignTo(1)) 143 require.True(t, nodeA.tryAssignTo(2)) 144 require.True(t, nodeA.tryAssignTo(2)) 145 }