github.com/safing/portbase@v0.19.5/database/storage/bbolt/bbolt_test.go (about)

     1  package bbolt
     2  
     3  import (
     4  	"context"
     5  	"os"
     6  	"reflect"
     7  	"sync"
     8  	"testing"
     9  	"time"
    10  
    11  	"github.com/safing/portbase/database/query"
    12  	"github.com/safing/portbase/database/record"
    13  	"github.com/safing/portbase/database/storage"
    14  )
    15  
    16  var (
    17  	// Compile time interface checks.
    18  	_ storage.Interface = &BBolt{}
    19  	_ storage.Batcher   = &BBolt{}
    20  	_ storage.Purger    = &BBolt{}
    21  )
    22  
    23  type TestRecord struct { //nolint:maligned
    24  	record.Base
    25  	sync.Mutex
    26  	S    string
    27  	I    int
    28  	I8   int8
    29  	I16  int16
    30  	I32  int32
    31  	I64  int64
    32  	UI   uint
    33  	UI8  uint8
    34  	UI16 uint16
    35  	UI32 uint32
    36  	UI64 uint64
    37  	F32  float32
    38  	F64  float64
    39  	B    bool
    40  }
    41  
    42  func TestBBolt(t *testing.T) {
    43  	t.Parallel()
    44  
    45  	testDir, err := os.MkdirTemp("", "testing-")
    46  	if err != nil {
    47  		t.Fatal(err)
    48  	}
    49  	defer func() {
    50  		_ = os.RemoveAll(testDir) // clean up
    51  	}()
    52  
    53  	// start
    54  	db, err := NewBBolt("test", testDir)
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  
    59  	a := &TestRecord{
    60  		S:    "banana",
    61  		I:    42,
    62  		I8:   42,
    63  		I16:  42,
    64  		I32:  42,
    65  		I64:  42,
    66  		UI:   42,
    67  		UI8:  42,
    68  		UI16: 42,
    69  		UI32: 42,
    70  		UI64: 42,
    71  		F32:  42.42,
    72  		F64:  42.42,
    73  		B:    true,
    74  	}
    75  	a.SetMeta(&record.Meta{})
    76  	a.Meta().Update()
    77  	a.SetKey("test:A")
    78  
    79  	// put record
    80  	_, err = db.Put(a)
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	// get and compare
    86  	r1, err := db.Get("A")
    87  	if err != nil {
    88  		t.Fatal(err)
    89  	}
    90  
    91  	a1 := &TestRecord{}
    92  	err = record.Unwrap(r1, a1)
    93  	if err != nil {
    94  		t.Fatal(err)
    95  	}
    96  
    97  	if !reflect.DeepEqual(a, a1) {
    98  		t.Fatalf("mismatch, got %v", a1)
    99  	}
   100  
   101  	// setup query test records
   102  	qA := &TestRecord{}
   103  	qA.SetKey("test:path/to/A")
   104  	qA.CreateMeta()
   105  	qB := &TestRecord{}
   106  	qB.SetKey("test:path/to/B")
   107  	qB.CreateMeta()
   108  	qC := &TestRecord{}
   109  	qC.SetKey("test:path/to/C")
   110  	qC.CreateMeta()
   111  	qZ := &TestRecord{}
   112  	qZ.SetKey("test:z")
   113  	qZ.CreateMeta()
   114  	// put
   115  	_, err = db.Put(qA)
   116  	if err == nil {
   117  		_, err = db.Put(qB)
   118  	}
   119  	if err == nil {
   120  		_, err = db.Put(qC)
   121  	}
   122  	if err == nil {
   123  		_, err = db.Put(qZ)
   124  	}
   125  	if err != nil {
   126  		t.Fatal(err)
   127  	}
   128  
   129  	// test query
   130  	q := query.New("test:path/to/").MustBeValid()
   131  	it, err := db.Query(q, true, true)
   132  	if err != nil {
   133  		t.Fatal(err)
   134  	}
   135  	cnt := 0
   136  	for range it.Next {
   137  		cnt++
   138  	}
   139  	if it.Err() != nil {
   140  		t.Fatal(it.Err())
   141  	}
   142  	if cnt != 3 {
   143  		t.Fatalf("unexpected query result count: %d", cnt)
   144  	}
   145  
   146  	// delete
   147  	err = db.Delete("A")
   148  	if err != nil {
   149  		t.Fatal(err)
   150  	}
   151  
   152  	// check if its gone
   153  	_, err = db.Get("A")
   154  	if err == nil {
   155  		t.Fatal("should fail")
   156  	}
   157  
   158  	// maintenance
   159  	err = db.MaintainRecordStates(context.TODO(), time.Now(), true)
   160  	if err != nil {
   161  		t.Fatal(err)
   162  	}
   163  
   164  	// maintenance
   165  	err = db.MaintainRecordStates(context.TODO(), time.Now(), false)
   166  	if err != nil {
   167  		t.Fatal(err)
   168  	}
   169  
   170  	// purging
   171  	purger, ok := db.(storage.Purger)
   172  	if ok {
   173  		n, err := purger.Purge(context.TODO(), query.New("test:path/to/").MustBeValid(), true, true, false)
   174  		if err != nil {
   175  			t.Fatal(err)
   176  		}
   177  		if n != 3 {
   178  			t.Fatalf("unexpected purge delete count: %d", n)
   179  		}
   180  	} else {
   181  		t.Fatal("should implement Purger")
   182  	}
   183  
   184  	// test query
   185  	q = query.New("test").MustBeValid()
   186  	it, err = db.Query(q, true, true)
   187  	if err != nil {
   188  		t.Fatal(err)
   189  	}
   190  	cnt = 0
   191  	for range it.Next {
   192  		cnt++
   193  	}
   194  	if it.Err() != nil {
   195  		t.Fatal(it.Err())
   196  	}
   197  	if cnt != 1 {
   198  		t.Fatalf("unexpected query result count: %d", cnt)
   199  	}
   200  
   201  	// shutdown
   202  	err = db.Shutdown()
   203  	if err != nil {
   204  		t.Fatal(err)
   205  	}
   206  }