gitlab.com/jokerrs1/Sia@v1.3.2/modules/consensus/subscribe_test.go (about) 1 package consensus 2 3 import ( 4 "testing" 5 6 "github.com/NebulousLabs/Sia/modules" 7 ) 8 9 // mockSubscriber receives and holds changes to the consensus set, remembering 10 // the order in which changes were received. 11 type mockSubscriber struct { 12 updates []modules.ConsensusChange 13 } 14 15 // newMockSubscriber returns a mockSubscriber that is ready to subscribe to a 16 // consensus set. Currently blank, but can be expanded to support more features 17 // in the future. 18 func newMockSubscriber() mockSubscriber { 19 return mockSubscriber{} 20 } 21 22 // ProcessConsensusChange adds a consensus change to the mock subscriber. 23 func (ms *mockSubscriber) ProcessConsensusChange(cc modules.ConsensusChange) { 24 ms.updates = append(ms.updates, cc) 25 } 26 27 // copySub creates and returns a new mock subscriber that has identical 28 // internals to the input mockSubscriber. The copy will not be subscribed to 29 // the consensus set even if the original is. 30 func (ms *mockSubscriber) copySub() (cms mockSubscriber) { 31 cms.updates = make([]modules.ConsensusChange, len(ms.updates)) 32 copy(cms.updates, ms.updates) 33 return cms 34 } 35 36 // TestInvalidConsensusChangeSubscription checks that the consensus set returns 37 // modules.ErrInvalidConsensusChangeID in the event of a subscriber using an 38 // unrecognized id. 39 func TestInvalidConsensusChangeSubscription(t *testing.T) { 40 if testing.Short() { 41 t.SkipNow() 42 } 43 t.Parallel() 44 cst, err := createConsensusSetTester(t.Name()) 45 if err != nil { 46 t.Fatal(err) 47 } 48 defer cst.Close() 49 50 ms := newMockSubscriber() 51 badCCID := modules.ConsensusChangeID{255, 255, 255} 52 err = cst.cs.ConsensusSetSubscribe(&ms, badCCID, cst.cs.tg.StopChan()) 53 if err != modules.ErrInvalidConsensusChangeID { 54 t.Error("consensus set returning the wrong error during an invalid subscription:", err) 55 } 56 57 cst.cs.mu.Lock() 58 for i := range cst.cs.subscribers { 59 if cst.cs.subscribers[i] == &ms { 60 t.Fatal("subscriber was not removed from subscriber list after an erroneus subscription") 61 } 62 } 63 cst.cs.mu.Unlock() 64 } 65 66 // TestInvalidToValidSubscription is a regression test. Previously, the 67 // consensus set would not unsubscribe a module if it returned an error during 68 // subscription. When the module resubscribed, the module would be 69 // double-subscribed to the consensus set. 70 func TestInvalidToValidSubscription(t *testing.T) { 71 if testing.Short() { 72 t.SkipNow() 73 } 74 t.Parallel() 75 cst, err := createConsensusSetTester(t.Name()) 76 if err != nil { 77 t.Fatal(err) 78 } 79 defer cst.Close() 80 81 // Start by performing a bad subscribe. 82 ms := newMockSubscriber() 83 badCCID := modules.ConsensusChangeID{255, 255, 255} 84 err = cst.cs.ConsensusSetSubscribe(&ms, badCCID, cst.cs.tg.StopChan()) 85 if err != modules.ErrInvalidConsensusChangeID { 86 t.Error("consensus set returning the wrong error during an invalid subscription:", err) 87 } 88 89 // Perform a correct subscribe. 90 err = cst.cs.ConsensusSetSubscribe(&ms, modules.ConsensusChangeBeginning, cst.cs.tg.StopChan()) 91 if err != nil { 92 t.Fatal(err) 93 } 94 95 // Mine a block and check that the mock subscriber only got a single 96 // consensus change. 97 numPrevUpdates := len(ms.updates) 98 _, err = cst.miner.AddBlock() 99 if err != nil { 100 t.Fatal(err) 101 } 102 if len(ms.updates) != numPrevUpdates+1 { 103 t.Error("subscriber received two consensus changes for a single block") 104 } 105 } 106 107 // TestUnsubscribe checks that the consensus set correctly unsubscribes a 108 // subscriber if the Unsubscribe call is made. 109 func TestUnsubscribe(t *testing.T) { 110 if testing.Short() { 111 t.SkipNow() 112 } 113 t.Parallel() 114 cst, err := createConsensusSetTester(t.Name()) 115 if err != nil { 116 t.Fatal(err) 117 } 118 defer cst.Close() 119 120 // Subscribe the mock subscriber to the consensus set. 121 ms := newMockSubscriber() 122 err = cst.cs.ConsensusSetSubscribe(&ms, modules.ConsensusChangeBeginning, cst.cs.tg.StopChan()) 123 if err != nil { 124 t.Fatal(err) 125 } 126 127 // Check that the subscriber is receiving updates. 128 msLen := len(ms.updates) 129 if msLen == 0 { 130 t.Error("mock subscriber is not receiving updates") 131 } 132 _, err = cst.miner.AddBlock() // should cause another update to be sent to the subscriber 133 if err != nil { 134 t.Fatal(err) 135 } 136 if len(ms.updates) != msLen+1 { 137 t.Error("mock subscriber did not receive the correct number of updates") 138 } 139 140 // Unsubscribe the subscriber and then check that it is no longer receiving 141 // updates. 142 cst.cs.Unsubscribe(&ms) 143 _, err = cst.miner.AddBlock() 144 if err != nil { 145 t.Fatal(err) 146 } 147 if len(ms.updates) != msLen+1 { 148 t.Error("mock subscriber was not correctly unsubscribed") 149 } 150 }