github.com/decred/dcrlnd@v0.7.6/channeldb/reports_test.go (about)

     1  package channeldb
     2  
     3  import (
     4  	"bytes"
     5  	"testing"
     6  
     7  	"github.com/decred/dcrd/chaincfg/chainhash"
     8  	"github.com/decred/dcrd/wire"
     9  	"github.com/decred/dcrlnd/kvdb"
    10  	"github.com/stretchr/testify/require"
    11  )
    12  
    13  var (
    14  	testChainHash = [chainhash.HashSize]byte{
    15  		0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
    16  		0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
    17  		0x2d, 0xe7, 0x93, 0xe4,
    18  	}
    19  
    20  	testChanPoint1 = wire.OutPoint{
    21  		Hash: chainhash.Hash{
    22  			0x51, 0xb6, 0x37, 0xd8, 0xfc, 0xd2, 0xc6, 0xda,
    23  			0x48, 0x59, 0xe6, 0x96, 0x31, 0x13, 0xa1, 0x17,
    24  			0x2d, 0xe7, 0x93, 0xe4,
    25  		},
    26  		Index: 1,
    27  	}
    28  )
    29  
    30  // TestPersistReport tests the writing and retrieval of a report on disk with
    31  // and without a spend txid.
    32  func TestPersistReport(t *testing.T) {
    33  	tests := []struct {
    34  		name      string
    35  		spendTxID *chainhash.Hash
    36  	}{
    37  		{
    38  			name:      "Non-nil spend txid",
    39  			spendTxID: &testChanPoint1.Hash,
    40  		},
    41  		{
    42  			name:      "Nil spend txid",
    43  			spendTxID: nil,
    44  		},
    45  	}
    46  
    47  	for _, test := range tests {
    48  		test := test
    49  
    50  		t.Run(test.name, func(t *testing.T) {
    51  			db, cleanup, err := MakeTestDB()
    52  			require.NoError(t, err)
    53  			defer cleanup()
    54  
    55  			channelOutpoint := testChanPoint1
    56  
    57  			testOutpoint := testChanPoint1
    58  			testOutpoint.Index++
    59  
    60  			report := &ResolverReport{
    61  				OutPoint:        testOutpoint,
    62  				Amount:          2,
    63  				ResolverType:    1,
    64  				ResolverOutcome: 2,
    65  				SpendTxID:       test.spendTxID,
    66  			}
    67  
    68  			// Write report to disk, and ensure it is identical when
    69  			// it is read.
    70  			err = db.PutResolverReport(
    71  				nil, testChainHash, &channelOutpoint, report,
    72  			)
    73  			require.NoError(t, err)
    74  
    75  			reports, err := db.FetchChannelReports(
    76  				testChainHash, &channelOutpoint,
    77  			)
    78  			require.NoError(t, err)
    79  			require.Equal(t, report, reports[0])
    80  		})
    81  	}
    82  }
    83  
    84  // TestFetchChannelReadBucket tests retrieval of the reports bucket for a
    85  // channel, testing that the appropriate error is returned based on the state
    86  // of the existing bucket.
    87  func TestFetchChannelReadBucket(t *testing.T) {
    88  	db, cleanup, err := MakeTestDB()
    89  	require.NoError(t, err)
    90  	defer cleanup()
    91  
    92  	channelOutpoint := testChanPoint1
    93  
    94  	testOutpoint := testChanPoint1
    95  	testOutpoint.Index++
    96  
    97  	// If we attempt to get reports when we do not have any present, we
    98  	// expect to fail because our chain hash bucket is not present.
    99  	_, err = db.FetchChannelReports(
   100  		testChainHash, &channelOutpoint,
   101  	)
   102  	require.Equal(t, ErrNoChainHashBucket, err)
   103  
   104  	// Finally we write a report to disk and check that we can fetch it.
   105  	report := &ResolverReport{
   106  		OutPoint:        testOutpoint,
   107  		Amount:          2,
   108  		ResolverOutcome: 1,
   109  		ResolverType:    2,
   110  		SpendTxID:       nil,
   111  	}
   112  
   113  	err = db.PutResolverReport(
   114  		nil, testChainHash, &channelOutpoint, report,
   115  	)
   116  	require.NoError(t, err)
   117  
   118  	// Now that the channel bucket exists, we expect the channel to be
   119  	// successfully fetched, with no reports.
   120  	reports, err := db.FetchChannelReports(testChainHash, &testChanPoint1)
   121  	require.NoError(t, err)
   122  	require.Equal(t, report, reports[0])
   123  }
   124  
   125  // TestFetchChannelWriteBucket tests the creation of missing buckets when
   126  // retrieving the reports bucket.
   127  func TestFetchChannelWriteBucket(t *testing.T) {
   128  	createReportsBucket := func(tx kvdb.RwTx) (kvdb.RwBucket, error) {
   129  		return tx.CreateTopLevelBucket(closedChannelBucket)
   130  	}
   131  
   132  	createChainHashBucket := func(reports kvdb.RwBucket) (kvdb.RwBucket,
   133  		error) {
   134  
   135  		return reports.CreateBucketIfNotExists(testChainHash[:])
   136  	}
   137  
   138  	createChannelBucket := func(chainHash kvdb.RwBucket) (kvdb.RwBucket,
   139  		error) {
   140  
   141  		var chanPointBuf bytes.Buffer
   142  		err := writeOutpoint(&chanPointBuf, &testChanPoint1)
   143  		require.NoError(t, err)
   144  
   145  		return chainHash.CreateBucketIfNotExists(chanPointBuf.Bytes())
   146  	}
   147  
   148  	tests := []struct {
   149  		name  string
   150  		setup func(tx kvdb.RwTx) error
   151  	}{
   152  		{
   153  			name: "no existing buckets",
   154  			setup: func(tx kvdb.RwTx) error {
   155  				return nil
   156  			},
   157  		},
   158  		{
   159  			name: "reports bucket exists",
   160  			setup: func(tx kvdb.RwTx) error {
   161  				_, err := createReportsBucket(tx)
   162  				return err
   163  			},
   164  		},
   165  		{
   166  			name: "chainhash bucket exists",
   167  			setup: func(tx kvdb.RwTx) error {
   168  				reports, err := createReportsBucket(tx)
   169  				if err != nil {
   170  					return err
   171  				}
   172  
   173  				_, err = createChainHashBucket(reports)
   174  				return err
   175  			},
   176  		},
   177  		{
   178  			name: "channel bucket exists",
   179  			setup: func(tx kvdb.RwTx) error {
   180  				reports, err := createReportsBucket(tx)
   181  				if err != nil {
   182  					return err
   183  				}
   184  
   185  				chainHash, err := createChainHashBucket(reports)
   186  				if err != nil {
   187  					return err
   188  				}
   189  
   190  				_, err = createChannelBucket(chainHash)
   191  				return err
   192  			},
   193  		},
   194  	}
   195  
   196  	for _, test := range tests {
   197  		test := test
   198  
   199  		t.Run(test.name, func(t *testing.T) {
   200  			db, cleanup, err := MakeTestDB()
   201  			require.NoError(t, err)
   202  			defer cleanup()
   203  
   204  			// Update our db to the starting state we expect.
   205  			err = kvdb.Update(db, test.setup, func() {})
   206  			require.NoError(t, err)
   207  
   208  			// Try to get our report bucket.
   209  			err = kvdb.Update(db, func(tx kvdb.RwTx) error {
   210  				_, err := fetchReportWriteBucket(
   211  					tx, testChainHash, &testChanPoint1,
   212  				)
   213  				return err
   214  			}, func() {})
   215  			require.NoError(t, err)
   216  		})
   217  	}
   218  }