From 0c8a15a9d54d4f1025aeba490e54afa5ad672fc5 Mon Sep 17 00:00:00 2001 From: Dave Collins Date: Mon, 14 Oct 2013 20:37:58 -0500 Subject: [PATCH] Add tests to verify integrity after clearing cache. This commit adds the infrastructure needed to re-run the integrity tests after calling the InvalidBlockCache, InvalidateTxCache, and InvalidateCache functions. The tests intentially randomize the order the invalidate functions are called in to increase the likelyhood of finding in issues realted to ordering of the calls. --- interface_test.go | 86 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 82 insertions(+), 4 deletions(-) diff --git a/interface_test.go b/interface_test.go index 288ca983..7bbcd781 100644 --- a/interface_test.go +++ b/interface_test.go @@ -14,7 +14,13 @@ import ( ) // testContext is used to store context information about a running test which -// is passed into helper functions. +// is passed into helper functions. The useSpends field indicates whether or +// not the spend data should be empty or figure it out based on the specific +// test blocks provided. This is needed because the first loop where the blocks +// are inserted, the tests are running against the latest block and therefore +// none of the outputs can be spent yet. However, on subsequent runs, all +// blocks have been inserted and therefore some of the transaction outputs are +// spent. type testContext struct { t *testing.T dbType string @@ -22,6 +28,7 @@ type testContext struct { blockHeight int64 blockHash *btcwire.ShaHash block *btcutil.Block + useSpends bool } // testInsertBlock ensures InsertBlock conforms to the interface contract. @@ -201,6 +208,46 @@ func testFetchTxBySha(tc *testContext) bool { return true } +// expectedSpentBuf returns the expected transaction spend information depending +// on the block height and and transaction number. NOTE: These figures are +// only valid for the specific set of test data provided at the time these tests +// were written. In particular, this means the first 256 blocks of the mainnet +// block chain. +// +// The first run through while the blocks are still being inserted, the tests +// are running against the latest block and therefore none of the outputs can +// be spent yet. However, on subsequent runs, all blocks have been inserted and +// therefore some of the transaction outputs are spent. +func expectedSpentBuf(tc *testContext, txNum int) []bool { + numTxOut := len(tc.block.MsgBlock().Transactions[txNum].TxOut) + spentBuf := make([]bool, numTxOut) + if tc.useSpends { + if tc.blockHeight == 9 && txNum == 0 { + spentBuf[0] = true + } + + if tc.blockHeight == 170 && txNum == 1 { + spentBuf[1] = true + } + + if tc.blockHeight == 181 && txNum == 1 { + spentBuf[1] = true + } + + if tc.blockHeight == 182 && txNum == 1 { + spentBuf[0] = true + spentBuf[1] = true + } + + if tc.blockHeight == 183 && txNum == 1 { + spentBuf[0] = true + spentBuf[1] = true + } + } + + return spentBuf +} + func testFetchTxByShaListCommon(tc *testContext, includeSpent bool) bool { fetchFunc := tc.db.FetchUnSpentTxByShaList funcName := "FetchUnSpentTxByShaList" @@ -291,12 +338,12 @@ func testFetchTxByShaListCommon(tc *testContext, includeSpent bool) bool { tc.blockHeight, tc.blockHash, i, txHash) return false } - noSpends := make([]bool, len(tx.TxOut)) - if !reflect.DeepEqual(txD.TxSpent, noSpends) { + spentBuf := expectedSpentBuf(tc, i) + if !reflect.DeepEqual(txD.TxSpent, spentBuf) { tc.t.Errorf("%s (%s): block #%d (%s) tx #%d (%s) "+ "returned unexpected spend data - got %v, "+ "want %v", funcName, tc.dbType, tc.blockHeight, - tc.blockHash, i, txHash, txD.TxSpent, noSpends) + tc.blockHash, i, txHash, txD.TxSpent, spentBuf) return false } } @@ -419,6 +466,37 @@ func testInterface(t *testing.T, dbType string) { } } + // The data integrity tests must still pass after calling each of the + // invalidate cache functions. This intentionally uses a map since + // map iteration is not the same order every run. This helps catch + // issues that could be caused by calling one version before another. + context.useSpends = true + invalidateCacheFuncs := map[string]func(){ + "InvalidateBlockCache": db.InvalidateBlockCache, + "InvalidateTxCache": db.InvalidateTxCache, + "InvalidateCache": db.InvalidateCache, + } + for funcName, invalidateCacheFunc := range invalidateCacheFuncs { + t.Logf("Running integrity tests after calling %s", funcName) + invalidateCacheFunc() + + for height := int64(0); height < int64(len(blocks)); height++ { + // Get the appropriate block and hash and update the + // test context accordingly. + block := blocks[height] + blockHash, err := block.Sha() + if err != nil { + t.Errorf("block.Sha: %v", err) + return + } + context.blockHeight = height + context.blockHash = blockHash + context.block = block + + testIntegrity(&context) + } + } + // TODO(davec): Need to figure out how to handle the special checks // required for the duplicate transactions allowed by blocks 91842 and // 91880 on the main network due to the old miner + Satoshi client bug.