all repos — postern

@ v0.1.0-alpha

Modern mail management

clone
git clone https:///postern.git

internal/db/kv_test.go (view raw)

  1package db
  2
  3import (
  4	"path"
  5	"sync"
  6	"testing"
  7)
  8
  9// TestKVInc tests that the KVInc function behaves correctly under concurrent access
 10func TestKVInc(t *testing.T) {
 11	posternDB, err := OpenDB(&Config{
 12		DBPath: path.Join(t.TempDir(), "meta.db"),
 13	})
 14	if err != nil {
 15		t.Fatal(err)
 16	}
 17
 18	defer func(posternDB *DB) {
 19		err := posternDB.Close()
 20		if err != nil {
 21			t.Fatal(err)
 22		}
 23	}(posternDB)
 24
 25	key := "test-concurrency-key"
 26	if err := posternDB.KVSet(t.Context(), key, 0); err != nil {
 27		t.Fatalf("KVSet setup failed: %v", err)
 28	}
 29
 30	const numGoroutines = 50
 31	const incsPerGoroutine = 200
 32
 33	var wg sync.WaitGroup
 34	wg.Add(numGoroutines)
 35
 36	for range numGoroutines {
 37		go func(db *DB) {
 38			defer wg.Done()
 39			for range incsPerGoroutine {
 40				_, err := db.KVInc(t.Context(), key, 1)
 41				if err != nil {
 42					t.Errorf("KVInc failed during execution: %v", err)
 43					return
 44				}
 45			}
 46		}(posternDB)
 47	}
 48
 49	wg.Wait()
 50
 51	// Retrieve the final count
 52	val, err := posternDB.KVGet(t.Context(), key)
 53	if err != nil {
 54		t.Fatalf("KVGet failed to fetch final value: %v", err)
 55	}
 56
 57	got, ok := val.(int64)
 58	if !ok {
 59		t.Fatalf("KVGet returned unexpected type: %T, expected int", val)
 60	}
 61
 62	// Catch race conditions
 63	expected := int64(numGoroutines * incsPerGoroutine)
 64	if got != expected {
 65		t.Errorf("Race condition detected! Expected final value %d, got %d", expected, got)
 66	}
 67
 68	// Check return value of next increment
 69	res, err := posternDB.KVInc(t.Context(), key, 1)
 70	if err != nil {
 71		t.Errorf("KVInc failed during execution: %v", err)
 72		return
 73	}
 74
 75	if res != expected+1 {
 76		t.Errorf("Incrementation mismatch! Expected final value %d, got %d", expected+1, res)
 77	}
 78}
 79
 80// TestKVList tests that the KVList function returns all stored key value pairs
 81func TestKVList(t *testing.T) {
 82	posternDB, err := OpenDB(&Config{
 83		DBPath: path.Join(t.TempDir(), "meta.db"),
 84	})
 85	if err != nil {
 86		t.Fatal(err)
 87	}
 88
 89	defer func(posternDB *DB) {
 90		err := posternDB.Close()
 91		if err != nil {
 92			t.Fatal(err)
 93		}
 94	}(posternDB)
 95
 96	want := map[string]any{
 97		"key-1": "value-1",
 98		"key-2": int64(42),
 99	}
100
101	for key, val := range want {
102		if err := posternDB.KVSet(t.Context(), key, val); err != nil {
103			t.Fatalf("KVSet setup failed: %v", err)
104		}
105	}
106
107	got, err := posternDB.KVList(t.Context())
108	if err != nil {
109		t.Fatalf("KVList failed: %v", err)
110	}
111
112	if len(got) != len(want) {
113		t.Fatalf("Expected %d pairs, got %d", len(want), len(got))
114	}
115
116	for key, expected := range want {
117		val, ok := got[key]
118		if !ok {
119			t.Errorf("Missing key %q in KVList result", key)
120			continue
121		}
122		if val != expected {
123			t.Errorf("Key %q: expected value %v, got %v", key, expected, val)
124		}
125	}
126}
127
128// TestKVIncString tests that the KVInc function does not increment invalid values
129func TestKVIncString(t *testing.T) {
130	posternDB, err := OpenDB(&Config{
131		DBPath: path.Join(t.TempDir(), "meta.db"),
132	})
133	if err != nil {
134		t.Fatal(err)
135	}
136
137	defer func(posternDB *DB) {
138		err := posternDB.Close()
139		if err != nil {
140			t.Fatal(err)
141		}
142	}(posternDB)
143
144	key := "test-key"
145	if err := posternDB.KVSet(t.Context(), key, "value"); err != nil {
146		t.Fatalf("KVSet setup failed: %v", err)
147	}
148
149	_, err = posternDB.KVInc(t.Context(), key, 1)
150	if err == nil {
151		t.Fatalf("KVInc should have failed during execution due to attempt incrementing a non-integer value")
152	}
153}
154
155// TestKVDelete tests the KVDelete function
156func TestKVDelete(t *testing.T) {
157	posternDB, err := OpenDB(&Config{
158		DBPath: path.Join(t.TempDir(), "meta.db"),
159	})
160	if err != nil {
161		t.Fatal(err)
162	}
163
164	defer func(posternDB *DB) {
165		err := posternDB.Close()
166		if err != nil {
167			t.Fatal(err)
168		}
169	}(posternDB)
170
171	key := "test-key"
172	var testVal int64 = 42
173	if err := posternDB.KVSet(t.Context(), key, testVal); err != nil {
174		t.Fatalf("KVSet setup failed: %v", err)
175	}
176
177	val, err := posternDB.KVPop(t.Context(), key)
178	if err != nil {
179		t.Fatalf("KVGet failed to fetch final value: %v", err)
180	}
181	if val != testVal {
182		t.Errorf("Expected value %d, got %d", testVal, val)
183	}
184
185	_, err = posternDB.KVPop(t.Context(), key)
186	if err == nil {
187		t.Fatalf("KVDelete should have failed during execution due to missing key")
188	}
189}