Skip to content
Snippets Groups Projects
Unverified Commit c4e7c5c5 authored by jonastheis's avatar jonastheis
Browse files

Add unit tests

parent a85eaf06
Branches
No related tags found
No related merge requests found
......@@ -67,10 +67,16 @@ func newBranch(branchID branchmanager.BranchID, liked bool) *Branch {
}
}
// LikableBrancher defines an interface for a likable branch.
type LikableBrancher interface {
ID() branchmanager.BranchID
Liked() bool
}
// AddTip adds the given value object as a tip in the given branch.
// If the branch is liked it is also added to t.tips.
// Parents are handled depending on the relation (same or different branch).
func (t *TipManager) AddTip(valueObject *payload.Payload, b *branchmanager.Branch) {
func (t *TipManager) AddTip(valueObject *payload.Payload, b LikableBrancher) {
t.mutex.Lock()
defer t.mutex.Unlock()
......@@ -115,17 +121,17 @@ func (t *TipManager) Tips() (parent1ObjectID, parent2ObjectID payload.ID) {
return
}
parent1ObjectID = tip.(Tip).id
parent1ObjectID = tip.(*Tip).id
if t.tips.Size() == 1 {
parent2ObjectID = parent1ObjectID
return
}
parent2ObjectID = t.tips.RandomEntry().(Tip).id
parent2ObjectID = t.tips.RandomEntry().(*Tip).id
// select 2 distinct tips if there's more than 1 tip available
for parent1ObjectID == parent2ObjectID && t.tips.Size() > 1 {
parent2ObjectID = t.tips.RandomEntry().(Tip).id
parent2ObjectID = t.tips.RandomEntry().(*Tip).id
}
return
......@@ -155,7 +161,7 @@ func (t *TipManager) OnBranchLiked(branchID branchmanager.BranchID) {
}
// remove tips from referenced branches
for objectID, _ := range branch.entryPoints {
for objectID := range branch.entryPoints {
t.tips.Delete(objectID)
}
}
......@@ -180,7 +186,7 @@ func (t *TipManager) OnBranchDisliked(branchID branchmanager.BranchID) {
}
}
// OnBranchDisliked is called when a branch is merged.
// OnBranchMerged is called when a branch is merged.
// TODO: it should perform some cleanup logic
func (t *TipManager) OnBranchMerged(branchID branchmanager.BranchID) {
// remove all tips from t.tips
......@@ -198,7 +204,11 @@ func removeTipAsEntryPoint(tip *Tip) {
// If the parent is in the same branch it is removed as a tip.
// If the parent is not in the same branch a two-way mapping from parent to branch and branch to parent is created.
func addTipHandleParent(parentID payload.ID, parentBranch *Branch, branch *Branch) {
parentTip := parentBranch.tips[parentID]
parentTip, ok := parentBranch.tips[parentID]
// parent is not a tip anymore
if !ok {
return
}
if parentBranch.branchID == branch.branchID {
// remove parents out of branch.tips
......
package tipmanager
import (
"sync"
"testing"
"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/address"
"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/balance"
"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/branchmanager"
"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/payload"
"github.com/iotaledger/goshimmer/dapps/valuetransfers/packages/transaction"
"github.com/stretchr/testify/assert"
)
/*
func TestTipManagerSimple(t *testing.T) {
tipManager := New()
......@@ -15,74 +20,193 @@ func TestTipManagerSimple(t *testing.T) {
assert.Equal(t, payload.GenesisID, parent1)
assert.Equal(t, payload.GenesisID, parent2)
// add few tips and check whether total tips count matches
totalTips := 100
branchesMap := make(map[branchmanager.BranchID]*payload.Payload, totalTips)
branches := make([]branchmanager.BranchID, totalTips)
for i := 0; i < totalTips; i++ {
branchID := branchmanager.NewBranchID(transaction.RandomID())
branches[i] = branchID
branchesMap[branchID] = payload.New(payload.GenesisID, payload.GenesisID, createDummyTransaction())
tipManager.AddTip(branchesMap[branchID], branchID)
}
assert.Equal(t, totalTips, tipManager.TipCount(branches...))
// add 1 transaction in liked branch -> both tips need to point there
tx := createDummyTransaction()
branch1 := newMockBranch(tx.ID(), true)
valueObject := payload.New(payload.GenesisID, payload.GenesisID, tx)
branch1.addTip(valueObject)
tipManager.AddTip(valueObject, branch1)
// check if tips point to genesis when branches are not found
parent1, parent2 = tipManager.Tips(branchmanager.UndefinedBranchID, branchmanager.NewBranchID(transaction.RandomID()))
assert.Equal(t, 0, tipManager.TipCount(branchmanager.UndefinedBranchID, branchmanager.NewBranchID(transaction.RandomID())))
assert.Equal(t, payload.GenesisID, parent1)
assert.Equal(t, payload.GenesisID, parent2)
assert.Equal(t, 1, tipManager.TipCount())
parent1, parent2 = tipManager.Tips()
assert.Equal(t, valueObject.ID(), parent1)
assert.Equal(t, valueObject.ID(), parent2)
// use each branch to get the single tip
for b, o := range branchesMap {
parent1ObjectID, parent2ObjectID := tipManager.Tips(b)
assert.Equal(t, o.ID(), parent1ObjectID)
assert.Equal(t, o.ID(), parent2ObjectID)
}
// add a bunch of liked tips -> check count
numTips := 10
branch2 := newMockBranch(transaction.RandomID(), true)
for i := 0; i < numTips; i++ {
v := payload.New(payload.GenesisID, payload.GenesisID, createDummyTransaction())
branch1.addTip(v)
tipManager.AddTip(v, branch1)
// select tips from two branches
parent1, parent2 = tipManager.Tips(branches[0], branches[1])
s := []payload.ID{
branchesMap[branches[0]].ID(),
branchesMap[branches[1]].ID(),
v = payload.New(payload.GenesisID, payload.GenesisID, createDummyTransaction())
branch2.addTip(v)
tipManager.AddTip(v, branch2)
}
assert.Contains(t, s, parent1)
assert.Contains(t, s, parent2)
}
func TestTipManagerParallel(t *testing.T) {
totalTips := 1000
totalThreads := 100
totalBranches := 10
assert.Equal(t, branch1.tipCount()+branch2.tipCount(), tipManager.TipCount())
assert.Equal(t, branch1.tipCount(), len(tipManager.branches[branch1.ID()].tips))
assert.Equal(t, branch2.tipCount(), len(tipManager.branches[branch2.ID()].tips))
parent1, parent2 = tipManager.Tips()
assert.NotEqual(t, parent1, parent2)
tipManager := New()
// add a bunch of disliked tips -> count should be unchanged
branch3 := newMockBranch(transaction.RandomID(), false)
branch4 := newMockBranch(transaction.RandomID(), false)
for i := 0; i < numTips; i++ {
v := payload.New(payload.GenesisID, payload.GenesisID, createDummyTransaction())
branch3.addTip(v)
tipManager.AddTip(v, branch3)
branches := make([]branchmanager.BranchID, totalBranches)
for i := 0; i < totalBranches; i++ {
branchID := branchmanager.NewBranchID(transaction.RandomID())
branches[i] = branchID
v = payload.New(payload.GenesisID, payload.GenesisID, createDummyTransaction())
branch4.addTip(v)
tipManager.AddTip(v, branch4)
}
// add tips in parallel
assert.Equal(t, branch1.tipCount()+branch2.tipCount(), tipManager.TipCount())
assert.Equal(t, branch1.tipCount(), len(tipManager.branches[branch1.ID()].tips))
assert.Equal(t, branch2.tipCount(), len(tipManager.branches[branch2.ID()].tips))
assert.Equal(t, branch3.tipCount(), len(tipManager.branches[branch3.ID()].tips))
assert.Equal(t, branch4.tipCount(), len(tipManager.branches[branch4.ID()].tips))
// add tip to liked branch with parents from same branch -> should be in tipmanager.tips and parents removed from tipmanager.tips and branch's tips
removedTip1 := branch1.tip()
removedTip2 := branch1.tip()
valueObject = payload.New(removedTip1, removedTip2, createDummyTransaction())
branch1.addTip(valueObject)
tipManager.AddTip(valueObject, branch1)
assert.Equal(t, branch1.tipCount()+branch2.tipCount(), tipManager.TipCount())
_, ok := tipManager.tips.Get(removedTip1)
assert.False(t, ok)
_, ok = tipManager.tips.Get(removedTip2)
assert.False(t, ok)
_, ok = tipManager.tips.Get(valueObject.ID())
assert.True(t, ok)
_, ok = tipManager.branches[branch1.ID()].tips[removedTip1]
assert.False(t, ok)
_, ok = tipManager.branches[branch1.ID()].tips[removedTip2]
assert.False(t, ok)
_, ok = tipManager.branches[branch1.ID()].tips[valueObject.ID()]
assert.True(t, ok)
// add tip to disliked branch with parents from same branch -> tipmanager.tips should be unmodified, only branch's tips modified
removedTip1 = branch3.tip()
removedTip2 = branch3.tip()
valueObject = payload.New(removedTip1, removedTip2, createDummyTransaction())
branch3.addTip(valueObject)
tipManager.AddTip(valueObject, branch3)
assert.Equal(t, branch1.tipCount()+branch2.tipCount(), tipManager.TipCount())
_, ok = tipManager.branches[branch3.ID()].tips[removedTip1]
assert.False(t, ok)
_, ok = tipManager.branches[branch3.ID()].tips[removedTip2]
assert.False(t, ok)
_, ok = tipManager.branches[branch3.ID()].tips[valueObject.ID()]
assert.True(t, ok)
}
// TestTipManagerParallel tests the TipManager's functionality by adding and selecting tips concurrently.
func TestTipManagerConcurrent(t *testing.T) {
numThreads := 10
numTips := 100
branches := make([]*mockBranch, numThreads)
tipManager := New()
var wg sync.WaitGroup
for i := 0; i < totalThreads; i++ {
// add tips to numThreads branches in parallel
for i := 0; i < numThreads; i++ {
wg.Add(1)
go func() {
go func(number int) {
defer wg.Done()
for t := 0; t < totalTips; t++ {
tip := payload.New(payload.GenesisID, payload.GenesisID, createDummyTransaction())
random := rand.Intn(totalBranches)
tipManager.AddTip(tip, branches[random])
branch := newMockBranch(transaction.RandomID(), number < numThreads/2)
branches[number] = branch
// add tips within a branch in parallel
var wg2 sync.WaitGroup
for t := 0; t < numTips; t++ {
v := payload.New(payload.GenesisID, payload.GenesisID, createDummyTransaction())
branch.addTip(v)
wg2.Add(1)
go func() {
defer wg2.Done()
tipManager.AddTip(v, branch)
}()
}
}()
wg2.Wait()
removedTip1 := branch.tip()
removedTip2 := branch.tip()
valueObject := payload.New(removedTip1, removedTip2, createDummyTransaction())
branch.addTip(valueObject)
tipManager.AddTip(valueObject, branch)
}(i)
}
wg.Wait()
// check total tip count
assert.Equal(t, totalTips*totalThreads, tipManager.TipCount(branches...))
// verify tips of every branch
for i := 0; i < numThreads; i++ {
branch := branches[i]
assert.Equal(t, branch.tipCount(), len(tipManager.branches[branch.ID()].tips))
for tip := range branch.tips {
// all tips should be in branch's list
_, ok := tipManager.branches[branch.ID()].tips[tip]
assert.True(t, ok)
// make sure that all tips from liked branches (and none from disliked branches) are in tipmanager.tips
_, ok = tipManager.tips.Get(tip)
assert.Equal(t, branch.Liked(), ok)
}
}
// total tips: numThreads/2 (liked branches) * numTips - numThreads/2 (selected tips)
assert.Equal(t, numThreads/2*numTips-numThreads/2, tipManager.TipCount())
}
type mockBranch struct {
id branchmanager.BranchID
liked bool
tips map[payload.ID]payload.ID
}
func newMockBranch(txID transaction.ID, liked bool) *mockBranch {
return &mockBranch{
id: branchmanager.NewBranchID(txID),
liked: liked,
tips: make(map[payload.ID]payload.ID),
}
}
func (m *mockBranch) ID() branchmanager.BranchID {
return m.id
}
func (m *mockBranch) Liked() bool {
return m.liked
}
func (m *mockBranch) addTip(valueObject *payload.Payload) {
m.tips[valueObject.ID()] = valueObject.ID()
}
func (m *mockBranch) tip() payload.ID {
var tip payload.ID
// get some element
for t := range m.tips {
tip = t
}
delete(m.tips, tip)
return tip
}
func (m *mockBranch) tipCount() int {
return len(m.tips)
}
*/
func createDummyTransaction() *transaction.Transaction {
return transaction.New(
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment