github.com/ethersphere/bee/v2@v2.2.0/pkg/storer/pinstore_test.go (about)

     1  // Copyright 2023 The Swarm Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package storer_test
     6  
     7  import (
     8  	"context"
     9  	"fmt"
    10  	"testing"
    11  	"time"
    12  
    13  	chunktesting "github.com/ethersphere/bee/v2/pkg/storage/testing"
    14  	storer "github.com/ethersphere/bee/v2/pkg/storer"
    15  	"github.com/ethersphere/bee/v2/pkg/swarm"
    16  )
    17  
    18  func testPinStore(t *testing.T, newStorer func() (*storer.DB, error)) {
    19  	t.Helper()
    20  
    21  	testCases := []struct {
    22  		chunks []swarm.Chunk
    23  		fail   bool
    24  	}{
    25  		{
    26  			chunks: chunktesting.GenerateTestRandomChunks(10),
    27  		},
    28  		{
    29  			chunks: chunktesting.GenerateTestRandomChunks(20),
    30  			fail:   true,
    31  		},
    32  		{
    33  			chunks: chunktesting.GenerateTestRandomChunks(30),
    34  		},
    35  	}
    36  
    37  	lstore, err := newStorer()
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  
    42  	for _, tc := range testCases {
    43  		testName := fmt.Sprintf("pin_%d_chunks", len(tc.chunks))
    44  		if tc.fail {
    45  			testName += "_rollback"
    46  		}
    47  		t.Run(testName, func(t *testing.T) {
    48  			session, err := lstore.NewCollection(context.TODO())
    49  			if err != nil {
    50  				t.Fatalf("NewCollection(...): unexpected error: %v", err)
    51  			}
    52  
    53  			for _, ch := range tc.chunks {
    54  				err := session.Put(context.TODO(), ch)
    55  				if err != nil {
    56  					t.Fatalf("session.Put(...): unexpected error: %v", err)
    57  					t.Fatal(err)
    58  				}
    59  			}
    60  
    61  			if tc.fail {
    62  				err := session.Cleanup()
    63  				if err != nil {
    64  					t.Fatalf("session.Cleanup(): unexpected error: %v", err)
    65  				}
    66  			} else {
    67  				err := session.Done(tc.chunks[0].Address())
    68  				if err != nil {
    69  					t.Fatalf("session.Done(...): unexpected error: %v", err)
    70  				}
    71  			}
    72  			verifyPinCollection(t, lstore.Storage(), tc.chunks[0], tc.chunks, !tc.fail)
    73  		})
    74  	}
    75  
    76  	for _, tc := range testCases {
    77  		t.Run("has "+tc.chunks[0].Address().String(), func(t *testing.T) {
    78  			hasFound, err := lstore.HasPin(tc.chunks[0].Address())
    79  			if err != nil {
    80  				t.Fatalf("HasPin(...): unexpected error: %v", err)
    81  			}
    82  			if hasFound != !tc.fail {
    83  				t.Fatalf("unexpected has chunk state: want %t have %t", !tc.fail, hasFound)
    84  			}
    85  		})
    86  	}
    87  
    88  	t.Run("pins", func(t *testing.T) {
    89  		pins, err := lstore.Pins()
    90  		if err != nil {
    91  			t.Fatalf("Pins(): unexpected error: %v", err)
    92  		}
    93  
    94  		want := 2
    95  		if len(pins) != want {
    96  			t.Fatalf("unexpected no of pins: want %d have %d", want, len(pins))
    97  		}
    98  	})
    99  
   100  	t.Run("delete pin", func(t *testing.T) {
   101  		t.Run("commit", func(t *testing.T) {
   102  			err := lstore.DeletePin(context.TODO(), testCases[2].chunks[0].Address())
   103  			if err != nil {
   104  				t.Fatalf("DeletePin(...): unexpected error: %v", err)
   105  			}
   106  
   107  			verifyPinCollection(t, lstore.Storage(), testCases[2].chunks[0], testCases[2].chunks, false)
   108  		})
   109  	})
   110  
   111  	t.Run("duplicate parallel upload does not leave orphaned chunks", func(t *testing.T) {
   112  		chunks := chunktesting.GenerateTestRandomChunks(4)
   113  
   114  		session1, err := lstore.NewCollection(context.TODO())
   115  		if err != nil {
   116  			t.Fatalf("NewCollection(...): unexpected error: %v", err)
   117  		}
   118  
   119  		session2, err := lstore.NewCollection(context.TODO())
   120  		if err != nil {
   121  			t.Fatalf("NewCollection2(...): unexpected error: %v", err)
   122  		}
   123  
   124  		for _, ch := range chunks {
   125  			err := session2.Put(context.TODO(), ch)
   126  			if err != nil {
   127  				t.Fatalf("session2.Put(...): unexpected error: %v", err)
   128  				t.Fatal(err)
   129  			}
   130  
   131  			err = session1.Put(context.TODO(), ch)
   132  			if err != nil {
   133  				t.Fatalf("session1.Put(...): unexpected error: %v", err)
   134  				t.Fatal(err)
   135  			}
   136  		}
   137  
   138  		err = session1.Done(chunks[0].Address())
   139  		if err != nil {
   140  			t.Fatalf("session1.Done(...): unexpected error: %v", err)
   141  		}
   142  
   143  		err = session2.Done(chunks[0].Address())
   144  		if err == nil {
   145  			t.Fatalf("session2.Done(...): expected error, got nil")
   146  		}
   147  
   148  		if err := session2.Cleanup(); err != nil {
   149  			t.Fatalf("session2.Done(...): unexpected error: %v", err)
   150  		}
   151  
   152  		verifyPinCollection(t, lstore.Storage(), chunks[0], chunks, true)
   153  		verifyChunkRefCount(t, lstore.Storage(), chunks)
   154  	})
   155  }
   156  
   157  func TestPinStore(t *testing.T) {
   158  	t.Parallel()
   159  
   160  	t.Run("inmem", func(t *testing.T) {
   161  		t.Parallel()
   162  
   163  		testPinStore(t, func() (*storer.DB, error) {
   164  			return storer.New(context.Background(), "", dbTestOps(swarm.RandAddress(t), 0, nil, nil, time.Second))
   165  		})
   166  	})
   167  	t.Run("disk", func(t *testing.T) {
   168  		t.Parallel()
   169  
   170  		testPinStore(t, diskStorer(t, dbTestOps(swarm.RandAddress(t), 0, nil, nil, time.Second)))
   171  	})
   172  }