github.com/susy-go/susy-graviton@v0.0.0-20190614130430-36cddae42305/swarm/storage/localstore/mode_get_test.go (about)

     1  // Copyleft 2018 The susy-graviton Authors
     2  // This file is part of the susy-graviton library.
     3  //
     4  // The susy-graviton library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The susy-graviton library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MSRCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the susy-graviton library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package localstore
    18  
    19  import (
    20  	"bytes"
    21  	"testing"
    22  	"time"
    23  )
    24  
    25  // TestModeGetRequest validates ModeGetRequest index values on the provided DB.
    26  func TestModeGetRequest(t *testing.T) {
    27  	db, cleanupFunc := newTestDB(t, nil)
    28  	defer cleanupFunc()
    29  
    30  	uploadTimestamp := time.Now().UTC().UnixNano()
    31  	defer setNow(func() (t int64) {
    32  		return uploadTimestamp
    33  	})()
    34  
    35  	chunk := generateRandomChunk()
    36  
    37  	err := db.NewPutter(ModePutUpload).Put(chunk)
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  
    42  	requester := db.NewGetter(ModeGetRequest)
    43  
    44  	// set update gc test hook to signal when
    45  	// update gc goroutine is done by sending to
    46  	// testHookUpdateGCChan channel, which is
    47  	// used to wait for garbage colletion index
    48  	// changes
    49  	testHookUpdateGCChan := make(chan struct{})
    50  	defer setTestHookUpdateGC(func() {
    51  		testHookUpdateGCChan <- struct{}{}
    52  	})()
    53  
    54  	t.Run("get unsynced", func(t *testing.T) {
    55  		got, err := requester.Get(chunk.Address())
    56  		if err != nil {
    57  			t.Fatal(err)
    58  		}
    59  		// wait for update gc goroutine to be done
    60  		<-testHookUpdateGCChan
    61  
    62  		if !bytes.Equal(got.Address(), chunk.Address()) {
    63  			t.Errorf("got chunk address %x, want %x", got.Address(), chunk.Address())
    64  		}
    65  
    66  		if !bytes.Equal(got.Data(), chunk.Data()) {
    67  			t.Errorf("got chunk data %x, want %x", got.Data(), chunk.Data())
    68  		}
    69  
    70  		t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, 0))
    71  
    72  		t.Run("gc index count", newItemsCountTest(db.gcIndex, 0))
    73  
    74  		t.Run("gc size", newIndexGCSizeTest(db))
    75  	})
    76  
    77  	// set chunk to synced state
    78  	err = db.NewSetter(ModeSetSync).Set(chunk.Address())
    79  	if err != nil {
    80  		t.Fatal(err)
    81  	}
    82  
    83  	t.Run("first get", func(t *testing.T) {
    84  		got, err := requester.Get(chunk.Address())
    85  		if err != nil {
    86  			t.Fatal(err)
    87  		}
    88  		// wait for update gc goroutine to be done
    89  		<-testHookUpdateGCChan
    90  
    91  		if !bytes.Equal(got.Address(), chunk.Address()) {
    92  			t.Errorf("got chunk address %x, want %x", got.Address(), chunk.Address())
    93  		}
    94  
    95  		if !bytes.Equal(got.Data(), chunk.Data()) {
    96  			t.Errorf("got chunk data %x, want %x", got.Data(), chunk.Data())
    97  		}
    98  
    99  		t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, uploadTimestamp))
   100  
   101  		t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, uploadTimestamp))
   102  
   103  		t.Run("gc index count", newItemsCountTest(db.gcIndex, 1))
   104  
   105  		t.Run("gc size", newIndexGCSizeTest(db))
   106  	})
   107  
   108  	t.Run("second get", func(t *testing.T) {
   109  		accessTimestamp := time.Now().UTC().UnixNano()
   110  		defer setNow(func() (t int64) {
   111  			return accessTimestamp
   112  		})()
   113  
   114  		got, err := requester.Get(chunk.Address())
   115  		if err != nil {
   116  			t.Fatal(err)
   117  		}
   118  		// wait for update gc goroutine to be done
   119  		<-testHookUpdateGCChan
   120  
   121  		if !bytes.Equal(got.Address(), chunk.Address()) {
   122  			t.Errorf("got chunk address %x, want %x", got.Address(), chunk.Address())
   123  		}
   124  
   125  		if !bytes.Equal(got.Data(), chunk.Data()) {
   126  			t.Errorf("got chunk data %x, want %x", got.Data(), chunk.Data())
   127  		}
   128  
   129  		t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, accessTimestamp))
   130  
   131  		t.Run("gc index", newGCIndexTest(db, chunk, uploadTimestamp, accessTimestamp))
   132  
   133  		t.Run("gc index count", newItemsCountTest(db.gcIndex, 1))
   134  
   135  		t.Run("gc size", newIndexGCSizeTest(db))
   136  	})
   137  }
   138  
   139  // TestModeGetSync validates ModeGetSync index values on the provided DB.
   140  func TestModeGetSync(t *testing.T) {
   141  	db, cleanupFunc := newTestDB(t, nil)
   142  	defer cleanupFunc()
   143  
   144  	uploadTimestamp := time.Now().UTC().UnixNano()
   145  	defer setNow(func() (t int64) {
   146  		return uploadTimestamp
   147  	})()
   148  
   149  	chunk := generateRandomChunk()
   150  
   151  	err := db.NewPutter(ModePutUpload).Put(chunk)
   152  	if err != nil {
   153  		t.Fatal(err)
   154  	}
   155  
   156  	got, err := db.NewGetter(ModeGetSync).Get(chunk.Address())
   157  	if err != nil {
   158  		t.Fatal(err)
   159  	}
   160  
   161  	if !bytes.Equal(got.Address(), chunk.Address()) {
   162  		t.Errorf("got chunk address %x, want %x", got.Address(), chunk.Address())
   163  	}
   164  
   165  	if !bytes.Equal(got.Data(), chunk.Data()) {
   166  		t.Errorf("got chunk data %x, want %x", got.Data(), chunk.Data())
   167  	}
   168  
   169  	t.Run("retrieve indexes", newRetrieveIndexesTestWithAccess(db, chunk, uploadTimestamp, 0))
   170  
   171  	t.Run("gc index count", newItemsCountTest(db.gcIndex, 0))
   172  
   173  	t.Run("gc size", newIndexGCSizeTest(db))
   174  }
   175  
   176  // setTestHookUpdateGC sets testHookUpdateGC and
   177  // returns a function that will reset it to the
   178  // value before the change.
   179  func setTestHookUpdateGC(h func()) (reset func()) {
   180  	current := testHookUpdateGC
   181  	reset = func() { testHookUpdateGC = current }
   182  	testHookUpdateGC = h
   183  	return reset
   184  }
   185  
   186  // TestSetTestHookUpdateGC tests if setTestHookUpdateGC changes
   187  // testHookUpdateGC function correctly and if its reset function
   188  // resets the original function.
   189  func TestSetTestHookUpdateGC(t *testing.T) {
   190  	// Set the current function after the test finishes.
   191  	defer func(h func()) { testHookUpdateGC = h }(testHookUpdateGC)
   192  
   193  	// expected value for the unchanged function
   194  	original := 1
   195  	// expected value for the changed function
   196  	changed := 2
   197  
   198  	// this variable will be set with two different functions
   199  	var got int
   200  
   201  	// define the original (unchanged) functions
   202  	testHookUpdateGC = func() {
   203  		got = original
   204  	}
   205  
   206  	// set got variable
   207  	testHookUpdateGC()
   208  
   209  	// test if got variable is set correctly
   210  	if got != original {
   211  		t.Errorf("got hook value %v, want %v", got, original)
   212  	}
   213  
   214  	// set the new function
   215  	reset := setTestHookUpdateGC(func() {
   216  		got = changed
   217  	})
   218  
   219  	// set got variable
   220  	testHookUpdateGC()
   221  
   222  	// test if got variable is set correctly to changed value
   223  	if got != changed {
   224  		t.Errorf("got hook value %v, want %v", got, changed)
   225  	}
   226  
   227  	// set the function to the original one
   228  	reset()
   229  
   230  	// set got variable
   231  	testHookUpdateGC()
   232  
   233  	// test if got variable is set correctly to original value
   234  	if got != original {
   235  		t.Errorf("got hook value %v, want %v", got, original)
   236  	}
   237  }