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  }