lbcd/blockchain/thresholdstate_test.go

196 lines
5.4 KiB
Go
Raw Normal View History

// Copyright (c) 2016 The btcsuite developers
// Use of this source code is governed by an ISC
// license that can be found in the LICENSE file.
package blockchain
import (
"testing"
"github.com/btcsuite/btcd/chaincfg/chainhash"
)
// TestThresholdStateStringer tests the stringized output for the
// ThresholdState type.
func TestThresholdStateStringer(t *testing.T) {
t.Parallel()
tests := []struct {
in ThresholdState
want string
}{
{ThresholdDefined, "ThresholdDefined"},
{ThresholdStarted, "ThresholdStarted"},
{ThresholdLockedIn, "ThresholdLockedIn"},
{ThresholdActive, "ThresholdActive"},
{ThresholdFailed, "ThresholdFailed"},
{0xff, "Unknown ThresholdState (255)"},
}
// Detect additional threshold states that don't have the stringer added.
if len(tests)-1 != int(numThresholdsStates) {
t.Errorf("It appears a threshold statewas added without " +
"adding an associated stringer test")
}
t.Logf("Running %d tests", len(tests))
for i, test := range tests {
result := test.in.String()
if result != test.want {
t.Errorf("String #%d\n got: %s want: %s", i, result,
test.want)
continue
}
}
}
// TestThresholdStateCache ensure the threshold state cache works as intended
// including adding entries, updating existing entries, and flushing.
func TestThresholdStateCache(t *testing.T) {
t.Parallel()
tests := []struct {
name string
numEntries int
state ThresholdState
}{
{name: "2 entries defined", numEntries: 2, state: ThresholdDefined},
{name: "7 entries started", numEntries: 7, state: ThresholdStarted},
{name: "10 entries active", numEntries: 10, state: ThresholdActive},
{name: "5 entries locked in", numEntries: 5, state: ThresholdLockedIn},
{name: "3 entries failed", numEntries: 3, state: ThresholdFailed},
}
nextTest:
for _, test := range tests {
cache := &newThresholdCaches(1)[0]
for i := 0; i < test.numEntries; i++ {
var hash chainhash.Hash
hash[0] = uint8(i + 1)
// Ensure the hash isn't available in the cache already.
_, ok := cache.Lookup(hash)
if ok {
t.Errorf("Lookup (%s): has entry for hash %v",
test.name, hash)
continue nextTest
}
// Ensure hash that was added to the cache reports it's
// available and the state is the expected value.
cache.Update(hash, test.state)
state, ok := cache.Lookup(hash)
if !ok {
t.Errorf("Lookup (%s): missing entry for hash "+
"%v", test.name, hash)
continue nextTest
}
if state != test.state {
t.Errorf("Lookup (%s): state mismatch - got "+
"%v, want %v", test.name, state,
test.state)
continue nextTest
}
// Ensure the update is also added to the internal
// database updates map and its state matches.
state, ok = cache.dbUpdates[hash]
if !ok {
t.Errorf("dbUpdates (%s): missing entry for "+
"hash %v", test.name, hash)
continue nextTest
}
if state != test.state {
t.Errorf("dbUpdates (%s): state mismatch - "+
"got %v, want %v", test.name, state,
test.state)
continue nextTest
}
// Ensure flushing the cache removes all entries from
// the internal database updates map.
cache.MarkFlushed()
if len(cache.dbUpdates) != 0 {
t.Errorf("dbUpdates (%s): unflushed entries",
test.name)
continue nextTest
}
// Ensure hash is still available in the cache and the
// state is the expected value.
state, ok = cache.Lookup(hash)
if !ok {
t.Errorf("Lookup (%s): missing entry after "+
"flush for hash %v", test.name, hash)
continue nextTest
}
if state != test.state {
t.Errorf("Lookup (%s): state mismatch after "+
"flush - got %v, want %v", test.name,
state, test.state)
continue nextTest
}
// Ensure adding an existing hash with the same state
// doesn't break the existing entry and it is NOT added
// to the database updates map.
cache.Update(hash, test.state)
state, ok = cache.Lookup(hash)
if !ok {
t.Errorf("Lookup (%s): missing entry after "+
"second add for hash %v", test.name,
hash)
continue nextTest
}
if state != test.state {
t.Errorf("Lookup (%s): state mismatch after "+
"second add - got %v, want %v",
test.name, state, test.state)
continue nextTest
}
if len(cache.dbUpdates) != 0 {
t.Errorf("dbUpdates (%s): unflushed entries "+
"after duplicate add", test.name)
continue nextTest
}
// Ensure adding an existing hash with a different state
// updates the existing entry.
newState := ThresholdFailed
if newState == test.state {
newState = ThresholdStarted
}
cache.Update(hash, newState)
state, ok = cache.Lookup(hash)
if !ok {
t.Errorf("Lookup (%s): missing entry after "+
"state change for hash %v", test.name,
hash)
continue nextTest
}
if state != newState {
t.Errorf("Lookup (%s): state mismatch after "+
"state change - got %v, want %v",
test.name, state, newState)
continue nextTest
}
// Ensure the update is also added to the internal
// database updates map and its state matches.
state, ok = cache.dbUpdates[hash]
if !ok {
t.Errorf("dbUpdates (%s): missing entry after "+
"state change for hash %v", test.name,
hash)
continue nextTest
}
if state != newState {
t.Errorf("dbUpdates (%s): state mismatch "+
"after state change - got %v, want %v",
test.name, state, newState)
continue nextTest
}
}
}
}