Skip to content

Commit

Permalink
Unit tests for list (#26)
Browse files Browse the repository at this point in the history
  • Loading branch information
outofforest authored Oct 5, 2024
1 parent 45c9d60 commit 9fb0619
Showing 1 changed file with 222 additions and 11 deletions.
233 changes: 222 additions & 11 deletions list/list_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
package list_test

import (
"sort"
"testing"

"github.com/samber/lo"
"github.com/stretchr/testify/require"

Expand All @@ -10,7 +13,191 @@ import (
"github.com/outofforest/quantum/types"
)

//nolint:unused
func TestAdd(t *testing.T) {
requireT := require.New(t)
e := newEnv(requireT)
l := e.NextSnapshot()

items := make([]types.NodeAddress, 0, 100)
for i := range types.NodeAddress(cap(items)) {
items = append(items, i)
requireT.NoError(l.Add(i))
}

requireT.Equal(items, collectListItems(l))

nodesAllocated, nodesDeallocated := e.Allocator.Nodes()
requireT.Equal([]types.NodeAddress{0x01, 0x02}, nodesAllocated)
requireT.Empty(nodesDeallocated)
requireT.Equal([]types.NodeAddress{0x01, 0x02}, l.Nodes())
}

func TestAttach(t *testing.T) {
requireT := require.New(t)
e := newEnv(requireT)
l := e.NextSnapshot()

items := make([]types.NodeAddress, 0, 1000)
var item types.NodeAddress
for range 100 {
l2Address, l2 := e.NewList(requireT)
for range 100 {
items = append(items, item)
requireT.NoError(l2.Add(item))
item++
}
requireT.NoError(l.Attach(*l2Address))
}

requireT.Equal(items, collectListItems(l))

nodesAllocated, nodesDeallocated := e.Allocator.Nodes()
requireT.Equal([]types.NodeAddress{
0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x12, 0x13,
0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25,
0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b,
0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d,
0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91,
0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3,
0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5,
0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
0xc8, 0xc9, 0xca,
}, nodesAllocated)
requireT.Empty(nodesDeallocated)
requireT.Equal(nodesAllocated, l.Nodes())
}

func TestAddAttach(t *testing.T) {
requireT := require.New(t)
e := newEnv(requireT)
l := e.NextSnapshot()

items := make([]types.NodeAddress, 0, 10000)
var item types.NodeAddress
for range 1000 {
l2Address, l2 := e.NewList(requireT)
for range 5 {
items = append(items, item)
requireT.NoError(l.Add(item))
item++

items = append(items, item)
requireT.NoError(l2.Add(item))
item++
}
requireT.NoError(l.Attach(*l2Address))
}

requireT.Equal(items, collectListItems(l))
}

func TestAttachTwoLevels(t *testing.T) {
requireT := require.New(t)
e := newEnv(requireT)
l := e.NextSnapshot()

items := make([]types.NodeAddress, 0, 10000)
var item types.NodeAddress
for range 100 {
l2Address, l2 := e.NewList(requireT)
for range 10 {
l3Address, l3 := e.NewList(requireT)

items = append(items, item)
requireT.NoError(l3.Add(item))
item++

requireT.NoError(l2.Attach(*l3Address))
}
requireT.NoError(l.Attach(*l2Address))
}

requireT.Equal(items, collectListItems(l))
}

func TestTwoSnapshots(t *testing.T) {
requireT := require.New(t)
e := newEnv(requireT)

// Snapshot 0

l0 := e.NextSnapshot()

items0 := make([]types.NodeAddress, 0, 100)
for i := range types.NodeAddress(cap(items0)) {
items0 = append(items0, i)
requireT.NoError(l0.Add(i))
}

requireT.Equal(items0, collectListItems(l0))

nodesAllocated, nodesDeallocated := e.Allocator.Nodes()
requireT.Equal([]types.NodeAddress{0x01, 0x02}, nodesAllocated)
requireT.Empty(nodesDeallocated)
requireT.Equal([]types.NodeAddress{0x01, 0x02}, l0.Nodes())

// Snapshot 1

items1 := make([]types.NodeAddress, 0, 2*cap(items0))
items1 = append(items1, items0...)

l1 := e.NextSnapshot()

for i := types.NodeAddress(cap(items0)); i < types.NodeAddress(cap(items1)); i++ {
items1 = append(items1, i)
requireT.NoError(l1.Add(i))
}

nodesAllocated, nodesDeallocated = e.Allocator.Nodes()
requireT.Equal([]types.NodeAddress{0x03, 0x04, 0x05}, nodesAllocated)
requireT.Equal([]types.NodeAddress{0x02}, nodesDeallocated)
requireT.Equal([]types.NodeAddress{0x01, 0x02}, l0.Nodes())
requireT.Equal([]types.NodeAddress{0x01, 0x03, 0x04, 0x05}, l1.Nodes())

requireT.Equal(items0, collectListItems(l0))
requireT.Equal(items1, collectListItems(l1))
}

func TestDeallocate(t *testing.T) {
requireT := require.New(t)
e := newEnv(requireT)
l := e.NextSnapshot()

nodeAddress, _, err := e.Allocator.Allocate(nil)
requireT.NoError(err)
requireT.NoError(l.Add(nodeAddress))

for range 10 {
l2Address, l2 := e.NewList(requireT)
nodeAddress, _, err := e.Allocator.Allocate(nil)
requireT.NoError(err)
requireT.NoError(l2.Add(nodeAddress))
for range 10 {
l3Address, l3 := e.NewList(requireT)
nodeAddress, _, err := e.Allocator.Allocate(nil)
requireT.NoError(err)

requireT.NoError(l3.Add(nodeAddress))

requireT.NoError(l2.Attach(*l3Address))
}
requireT.NoError(l.Attach(*l2Address))
}

nodesAllocated1, nodesDeallocated1 := e.Allocator.Nodes()
requireT.NotEmpty(nodesAllocated1)
requireT.Empty(nodesDeallocated1)

l.Deallocate(e.Allocator)

nodesAllocated2, nodesDeallocated2 := e.Allocator.Nodes()
requireT.Empty(nodesAllocated2)
requireT.Equal(nodesAllocated1, nodesDeallocated2)
}

func newEnv(requireT *require.Assertions) *env {
allocator := alloc.NewTestAllocator(alloc.NewAllocator(alloc.Config{
TotalSize: 1024 * 1024,
Expand All @@ -27,32 +214,56 @@ func newEnv(requireT *require.Assertions) *env {
}
}

//nolint:unused
type env struct {
Allocator *alloc.TestAllocator
Item *types.NodeAddress

snapshotID types.SnapshotID
nodeAllocator list.NodeAllocator
snapshotID types.SnapshotID
snapshotAllocator alloc.SnapshotAllocator
nodeAllocator list.NodeAllocator
}

//nolint:unused
func (e *env) NextSnapshot() *list.List {
snapshotID := e.snapshotID
e.snapshotID++

itemCopy := *e.Item
e.Item = &itemCopy

e.snapshotAllocator = alloc.NewSnapshotAllocator(
snapshotID,
e.Allocator,
&space.Space[types.SnapshotID, types.NodeAddress]{},
e.nodeAllocator,
)

return list.New(list.Config{
SnapshotID: snapshotID,
Item: e.Item,
NodeAllocator: e.nodeAllocator,
Allocator: alloc.NewSnapshotAllocator(
snapshotID,
e.Allocator,
&space.Space[types.SnapshotID, types.NodeAddress]{},
e.nodeAllocator,
),
Allocator: e.snapshotAllocator,
})
}

func (e *env) NewList(requireT *require.Assertions) (*types.NodeAddress, *list.List) {
nodeAddress := lo.ToPtr[types.NodeAddress](0)
snapshotID := e.snapshotID - 1
return nodeAddress, list.New(list.Config{
SnapshotID: snapshotID,
Item: nodeAddress,
NodeAllocator: e.nodeAllocator,
Allocator: e.snapshotAllocator,
})
}

func collectListItems(l *list.List) []types.NodeAddress {
items := []types.NodeAddress{}
for item := range l.Iterator() {
items = append(items, item)
}

sort.Slice(items, func(i, j int) bool {
return items[i] < items[j]
})
return items
}

0 comments on commit 9fb0619

Please sign in to comment.