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

Add unit tests

parent a85eaf06
Branches
Tags
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