Skip to content

Commit

Permalink
Add unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
qdm12 committed Jun 2, 2022
1 parent 6e02682 commit 2170947
Show file tree
Hide file tree
Showing 2 changed files with 238 additions and 1 deletion.
2 changes: 1 addition & 1 deletion dot/sync/block_queue.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ func (bq *blockQueue) push(blockData *types.BlockData) {
func (bq *blockQueue) pop(ctx context.Context) (blockData *types.BlockData) {
select {
case <-ctx.Done():
return
return nil
case blockData = <-bq.queue:
}
bq.hashesSetMutex.Lock()
Expand Down
237 changes: 237 additions & 0 deletions dot/sync/block_queue_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
// Copyright 2021 ChainSafe Systems (ON)
// SPDX-License-Identifier: LGPL-3.0-only

package sync

import (
"context"
"sync"
"testing"
"time"

"github.com/ChainSafe/gossamer/dot/types"
"github.com/ChainSafe/gossamer/lib/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func Test_newBlockQueue(t *testing.T) {
t.Parallel()

const capacity = 1
bq := newBlockQueue(capacity)

require.NotNil(t, bq.queue)
assert.Equal(t, 1, cap(bq.queue))
assert.Equal(t, 0, len(bq.queue))
bq.queue = nil

expectedBlockQueue := &blockQueue{
hashesSet: make(map[common.Hash]struct{}, capacity),
}
assert.Equal(t, expectedBlockQueue, bq)
}

func Test_blockQueue_push(t *testing.T) {
t.Parallel()

const capacity = 1
bq := newBlockQueue(capacity)
blockData := &types.BlockData{
Hash: common.Hash{1},
}

bq.push(blockData)

// cannot compare channels
require.NotNil(t, bq.queue)
assert.Len(t, bq.queue, 1)

receivedBlockData := <-bq.queue
expectedBlockData := &types.BlockData{
Hash: common.Hash{1},
}
assert.Equal(t, expectedBlockData, receivedBlockData)

bq.queue = nil
expectedBlockQueue := &blockQueue{
hashesSet: map[common.Hash]struct{}{{1}: {}},
}
assert.Equal(t, expectedBlockQueue, bq)
}

func Test_blockQueue_pop(t *testing.T) {
t.Parallel()

t.Run("context canceled", func(t *testing.T) {
t.Parallel()

ctx, cancel := context.WithCancel(context.Background())
cancel()

const capacity = 1
bq := newBlockQueue(capacity)

blockData := bq.pop(ctx)
assert.Nil(t, blockData)
})

t.Run("get block data after waiting", func(t *testing.T) {
t.Parallel()

ctx := context.Background()

const capacity = 1
bq := newBlockQueue(capacity)

const afterDuration = 5 * time.Millisecond
time.AfterFunc(afterDuration, func() {
blockData := &types.BlockData{
Hash: common.Hash{1},
}
bq.push(blockData)
})

blockData := bq.pop(ctx)

expectedBlockData := &types.BlockData{
Hash: common.Hash{1},
}
assert.Equal(t, expectedBlockData, blockData)

assert.Len(t, bq.queue, 0)
bq.queue = nil
expectedBlockQueue := &blockQueue{
hashesSet: map[common.Hash]struct{}{},
}
assert.Equal(t, expectedBlockQueue, bq)
})
}

func Test_blockQueue_has(t *testing.T) {
t.Parallel()

testCases := map[string]struct {
blockQueue *blockQueue
blockHash common.Hash
has bool
}{
"absent": {
blockQueue: &blockQueue{
hashesSet: map[common.Hash]struct{}{},
},
blockHash: common.Hash{1},
},
"exists": {
blockQueue: &blockQueue{
hashesSet: map[common.Hash]struct{}{{1}: {}},
},
blockHash: common.Hash{1},
has: true,
},
}

for name, tc := range testCases {
testCase := tc
t.Run(name, func(t *testing.T) {
t.Parallel()

has := testCase.blockQueue.has(testCase.blockHash)
assert.Equal(t, testCase.has, has)
})
}
}

func Test_lockQueue_endToEnd(t *testing.T) {
t.Parallel()

const capacity = 10
blockQueue := newBlockQueue(capacity)

newBlockData := func(i byte) *types.BlockData {
return &types.BlockData{
Hash: common.Hash{i},
}
}

blockQueue.push(newBlockData(1))
blockQueue.push(newBlockData(2))
blockQueue.push(newBlockData(3))

blockData := blockQueue.pop(context.Background())
assert.Equal(t, newBlockData(1), blockData)

has := blockQueue.has(newBlockData(2).Hash)
assert.True(t, has)
has = blockQueue.has(newBlockData(3).Hash)
assert.True(t, has)

blockQueue.push(newBlockData(4))

has = blockQueue.has(newBlockData(4).Hash)
assert.True(t, has)

blockData = blockQueue.pop(context.Background())
assert.Equal(t, newBlockData(2), blockData)

// drain queue
for len(blockQueue.queue) > 0 {
<-blockQueue.queue
}
}

func Test_lockQueue_threadSafety(t *testing.T) {
// This test consists in checking for concurrent access
// using the -race detector.
t.Parallel()

var startWg, endWg sync.WaitGroup
ctx, cancel := context.WithCancel(context.Background())

const operations = 3
const parallelism = 3
const goroutines = parallelism * operations
startWg.Add(goroutines)
endWg.Add(goroutines)

const testDuration = 50 * time.Millisecond
go func() {
timer := time.NewTimer(time.Hour)
startWg.Wait()
_ = timer.Reset(testDuration)
<-timer.C
cancel()
}()

runInLoop := func(f func()) {
defer endWg.Done()
startWg.Done()
startWg.Wait()
for ctx.Err() == nil {
f()
}
}

const capacity = 10
blockQueue := newBlockQueue(capacity)
blockData := &types.BlockData{
Hash: common.Hash{1},
}
blockHash := common.Hash{1}

for i := 0; i < parallelism; i++ {
go runInLoop(func() {
blockQueue.push(blockData)
})

go runInLoop(func() {
_ = blockQueue.pop(ctx)
})

go runInLoop(func() {
_ = blockQueue.has(blockHash)
})
}

endWg.Wait()
}

0 comments on commit 2170947

Please sign in to comment.