From 818270ae4d1d2cec5bc9996c3798a57019f4313b Mon Sep 17 00:00:00 2001
From: Wolfgang Welz <welzwo@gmail.com>
Date: Thu, 18 Jun 2020 18:57:06 +0200
Subject: [PATCH] Add BranchManager event tests (#480)

* test that the correct events are triggered

* assure that all events are mocked

* cleanup event wrapper
---
 .../branchmanager/branchmanager_test.go       | 126 ++++++++++++++++++
 1 file changed, 126 insertions(+)

diff --git a/dapps/valuetransfers/packages/branchmanager/branchmanager_test.go b/dapps/valuetransfers/packages/branchmanager/branchmanager_test.go
index e5a148f6..268499b7 100644
--- a/dapps/valuetransfers/packages/branchmanager/branchmanager_test.go
+++ b/dapps/valuetransfers/packages/branchmanager/branchmanager_test.go
@@ -1,10 +1,13 @@
 package branchmanager
 
 import (
+	"reflect"
 	"testing"
 
+	"github.com/iotaledger/hive.go/events"
 	"github.com/iotaledger/hive.go/kvstore/mapdb"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/mock"
 )
 
 type sampleTree struct {
@@ -22,6 +25,92 @@ func (st *sampleTree) Release() {
 	}
 }
 
+// eventMock is a wrapper around mock.Mock used to test the triggered events.
+type eventMock struct {
+	mock.Mock
+
+	attached []struct {
+		*events.Event
+		*events.Closure
+	}
+}
+
+func newEventMock(t *testing.T, mgr *BranchManager) *eventMock {
+	e := &eventMock{}
+	e.Test(t)
+
+	// attach all events
+	e.attach(mgr.Events.BranchConfirmed, e.BranchConfirmed)
+	e.attach(mgr.Events.BranchDisliked, e.BranchDisliked)
+	e.attach(mgr.Events.BranchFinalized, e.BranchFinalized)
+	e.attach(mgr.Events.BranchLiked, e.BranchLiked)
+	e.attach(mgr.Events.BranchPreferred, e.BranchPreferred)
+	e.attach(mgr.Events.BranchRejected, e.BranchRejected)
+	e.attach(mgr.Events.BranchUnpreferred, e.BranchUnpreferred)
+
+	// assure that all available events are mocked
+	numEvents := reflect.ValueOf(mgr.Events).Elem().NumField()
+	assert.Equalf(t, len(e.attached), numEvents, "not all events in BranchManager.Events have been attached")
+
+	return e
+}
+
+// DetachAll detaches all attached event mocks.
+func (e *eventMock) DetachAll() {
+	for _, a := range e.attached {
+		a.Event.Detach(a.Closure)
+	}
+}
+
+// Expect starts a description of an expectation of the specified event being triggered.
+func (e *eventMock) Expect(eventName string, arguments ...interface{}) {
+	e.On(eventName, arguments...)
+}
+
+func (e *eventMock) attach(event *events.Event, f interface{}) {
+	closure := events.NewClosure(f)
+	event.Attach(closure)
+	e.attached = append(e.attached, struct {
+		*events.Event
+		*events.Closure
+	}{event, closure})
+}
+
+func (e *eventMock) BranchConfirmed(cachedBranch *CachedBranch) {
+	defer cachedBranch.Release()
+	e.Called(cachedBranch.Unwrap())
+}
+
+func (e *eventMock) BranchDisliked(cachedBranch *CachedBranch) {
+	defer cachedBranch.Release()
+	e.Called(cachedBranch.Unwrap())
+}
+
+func (e *eventMock) BranchFinalized(cachedBranch *CachedBranch) {
+	defer cachedBranch.Release()
+	e.Called(cachedBranch.Unwrap())
+}
+
+func (e *eventMock) BranchLiked(cachedBranch *CachedBranch) {
+	defer cachedBranch.Release()
+	e.Called(cachedBranch.Unwrap())
+}
+
+func (e *eventMock) BranchPreferred(cachedBranch *CachedBranch) {
+	defer cachedBranch.Release()
+	e.Called(cachedBranch.Unwrap())
+}
+
+func (e *eventMock) BranchRejected(cachedBranch *CachedBranch) {
+	defer cachedBranch.Release()
+	e.Called(cachedBranch.Unwrap())
+}
+
+func (e *eventMock) BranchUnpreferred(cachedBranch *CachedBranch) {
+	defer cachedBranch.Release()
+	e.Called(cachedBranch.Unwrap())
+}
+
 // ./img/sample_tree.png
 func createSampleTree(branchManager *BranchManager) *sampleTree {
 	st := &sampleTree{
@@ -857,6 +946,8 @@ func TestBranchManager_BranchesConflicting(t *testing.T) {
 
 func TestBranchManager_SetBranchPreferred(t *testing.T) {
 	branchManager := New(mapdb.NewMapDB())
+	event := newEventMock(t, branchManager)
+	defer event.DetachAll()
 
 	cachedBranch2, _ := branchManager.Fork(BranchID{2}, []BranchID{MasterBranchID}, []ConflictID{{0}})
 	defer cachedBranch2.Release()
@@ -882,6 +973,9 @@ func TestBranchManager_SetBranchPreferred(t *testing.T) {
 	// lets assume branch 4 is preferred since its underlying transaction was longer
 	// solid than the avg. network delay before the conflicting transaction which created
 	// the conflict set was received
+
+	event.Expect("BranchPreferred", branch4)
+
 	modified, err := branchManager.SetBranchPreferred(branch4.ID(), true)
 	assert.NoError(t, err)
 	assert.True(t, modified)
@@ -894,6 +988,11 @@ func TestBranchManager_SetBranchPreferred(t *testing.T) {
 
 	// now branch 2 becomes preferred via FPC, this causes branch 2 to be liked (since
 	// the master branch is liked) and its liked state propagates to branch 4 (but not branch 5)
+
+	event.Expect("BranchPreferred", branch2)
+	event.Expect("BranchLiked", branch2)
+	event.Expect("BranchLiked", branch4)
+
 	modified, err = branchManager.SetBranchPreferred(branch2.ID(), true)
 	assert.NoError(t, err)
 	assert.True(t, modified)
@@ -907,6 +1006,12 @@ func TestBranchManager_SetBranchPreferred(t *testing.T) {
 
 	// now the network decides that branch 5 is preferred (via FPC), thus branch 4 should lose its
 	// preferred and liked state and branch 5 should instead become preferred and liked
+
+	event.Expect("BranchPreferred", branch5)
+	event.Expect("BranchLiked", branch5)
+	event.Expect("BranchUnpreferred", branch4)
+	event.Expect("BranchDisliked", branch4)
+
 	modified, err = branchManager.SetBranchPreferred(branch5.ID(), true)
 	assert.NoError(t, err)
 	assert.True(t, modified)
@@ -920,10 +1025,15 @@ func TestBranchManager_SetBranchPreferred(t *testing.T) {
 	assert.False(t, branch4.Preferred(), "branch 4 should not be preferred")
 	assert.True(t, branch5.Liked(), "branch 5 should be liked")
 	assert.True(t, branch5.Preferred(), "branch 5 should be preferred")
+
+	// check that all event have been triggered
+	event.AssertExpectations(t)
 }
 
 func TestBranchManager_SetBranchPreferred2(t *testing.T) {
 	branchManager := New(mapdb.NewMapDB())
+	event := newEventMock(t, branchManager)
+	defer event.DetachAll()
 
 	cachedBranch2, _ := branchManager.Fork(BranchID{2}, []BranchID{MasterBranchID}, []ConflictID{{0}})
 	defer cachedBranch2.Release()
@@ -949,6 +1059,11 @@ func TestBranchManager_SetBranchPreferred2(t *testing.T) {
 	defer cachedBranch7.Release()
 	branch7 := cachedBranch7.Unwrap()
 
+	event.Expect("BranchPreferred", branch2)
+	event.Expect("BranchLiked", branch2)
+	event.Expect("BranchPreferred", branch6)
+	event.Expect("BranchLiked", branch6)
+
 	// assume branch 2 preferred since solid longer than avg. network delay
 	modified, err := branchManager.SetBranchPreferred(branch2.ID(), true)
 	assert.NoError(t, err)
@@ -1031,13 +1146,21 @@ func TestBranchManager_SetBranchPreferred2(t *testing.T) {
 	// should also become liked, since branch 2 of which it spawns off is liked too.
 
 	// simulate branch 3 being not preferred from FPC vote
+	// this does not trigger any events as branch 3 was never preferred
 	modified, err = branchManager.SetBranchPreferred(branch3.ID(), false)
 	assert.NoError(t, err)
 	assert.False(t, modified)
 	// simulate branch 7 being not preferred from FPC vote
+	// this does not trigger any events as branch 7 was never preferred
 	modified, err = branchManager.SetBranchPreferred(branch7.ID(), false)
 	assert.NoError(t, err)
 	assert.False(t, modified)
+
+	event.Expect("BranchPreferred", branch4)
+	event.Expect("BranchLiked", branch4)
+	event.Expect("BranchPreferred", aggrBranch8)
+	event.Expect("BranchLiked", aggrBranch8)
+
 	// simulate branch 4 being preferred by FPC vote
 	modified, err = branchManager.SetBranchPreferred(branch4.ID(), true)
 	assert.NoError(t, err)
@@ -1049,4 +1172,7 @@ func TestBranchManager_SetBranchPreferred2(t *testing.T) {
 	// of which it spawns off are.
 	assert.True(t, aggrBranch8.Liked(), "aggr. branch 8 should be liked")
 	assert.True(t, aggrBranch8.Preferred(), "aggr. branch 8 should be preferred")
+
+	// check that all event have been triggered
+	event.AssertExpectations(t)
 }
-- 
GitLab