File: keyvaluestore_test.go

package info (click to toggle)
git-lfs 3.6.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 4,808 kB
  • sloc: sh: 21,256; makefile: 507; ruby: 417
file content (185 lines) | stat: -rw-r--r-- 4,489 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
package kv

import (
	"os"
	"testing"

	"github.com/stretchr/testify/assert"
)

func TestStoreSimple(t *testing.T) {
	tmpf, err := os.CreateTemp("", "lfstest1")
	assert.Nil(t, err)
	filename := tmpf.Name()
	defer os.Remove(filename)
	tmpf.Close()

	kvs, err := NewStore(filename)
	assert.Nil(t, err)

	// We'll include storing custom structs
	type customData struct {
		Val1 string
		Val2 int
	}
	// Needed to store custom struct
	RegisterTypeForStorage(&customData{})

	kvs.Set("stringVal", "This is a string value")
	kvs.Set("intVal", 3)
	kvs.Set("floatVal", 3.142)
	kvs.Set("structVal", &customData{"structTest", 20})

	s := kvs.Get("stringVal")
	assert.Equal(t, "This is a string value", s)
	i := kvs.Get("intVal")
	assert.Equal(t, 3, i)
	f := kvs.Get("floatVal")
	assert.Equal(t, 3.142, f)
	c := kvs.Get("structVal")
	assert.Equal(t, c, &customData{"structTest", 20})
	n := kvs.Get("noValue")
	assert.Nil(t, n)

	kvs.Remove("stringVal")
	s = kvs.Get("stringVal")
	assert.Nil(t, s)
	// Set the string value again before saving
	kvs.Set("stringVal", "This is a string value")

	err = kvs.Save()
	assert.Nil(t, err)
	kvs = nil

	// Now confirm that we can read it all back
	kvs2, err := NewStore(filename)
	assert.Nil(t, err)
	s = kvs2.Get("stringVal")
	assert.Equal(t, "This is a string value", s)
	i = kvs2.Get("intVal")
	assert.Equal(t, 3, i)
	f = kvs2.Get("floatVal")
	assert.Equal(t, 3.142, f)
	c = kvs2.Get("structVal")
	assert.Equal(t, c, &customData{"structTest", 20})
	n = kvs2.Get("noValue")
	assert.Nil(t, n)

	// Test remove all
	kvs2.RemoveAll()
	s = kvs2.Get("stringVal")
	assert.Nil(t, s)
	i = kvs2.Get("intVal")
	assert.Nil(t, i)
	f = kvs2.Get("floatVal")
	assert.Nil(t, f)
	c = kvs2.Get("structVal")
	assert.Nil(t, c)

	err = kvs2.Save()
	assert.Nil(t, err)
	kvs2 = nil

	// Now confirm that we can read blank & get nothing
	kvs, err = NewStore(filename)
	assert.Nil(t, err)
	kvs.Visit(func(k string, v interface{}) bool {
		// Should not be called
		assert.Fail(t, "Should be no entries")
		return true
	})
}

func TestStoreOptimisticConflict(t *testing.T) {
	tmpf, err := os.CreateTemp("", "lfstest2")
	assert.Nil(t, err)
	filename := tmpf.Name()
	defer os.Remove(filename)
	tmpf.Close()

	kvs1, err := NewStore(filename)
	assert.Nil(t, err)

	kvs1.Set("key1", "value1")
	kvs1.Set("key2", "value2")
	kvs1.Set("key3", "value3")
	err = kvs1.Save()
	assert.Nil(t, err)

	// Load second copy & modify
	kvs2, err := NewStore(filename)
	assert.Nil(t, err)
	// New keys
	kvs2.Set("key4", "value4_fromkvs2")
	kvs2.Set("key5", "value5_fromkvs2")
	// Modify a key too
	kvs2.Set("key1", "value1_fromkvs2")
	err = kvs2.Save()
	assert.Nil(t, err)

	// Now modify first copy & save; it should detect optimistic lock issue
	// New item
	kvs1.Set("key10", "value10")
	// Overlapping item; since we save second this will overwrite one from kvs2
	kvs1.Set("key4", "value4")
	err = kvs1.Save()
	assert.Nil(t, err)

	// This should have merged changes from kvs2 in the process
	v := kvs1.Get("key1")
	assert.Equal(t, "value1_fromkvs2", v) // this one was modified by kvs2
	v = kvs1.Get("key2")
	assert.Equal(t, "value2", v)
	v = kvs1.Get("key3")
	assert.Equal(t, "value3", v)
	v = kvs1.Get("key4")
	assert.Equal(t, "value4", v) // we overwrote this so would not be merged
	v = kvs1.Get("key5")
	assert.Equal(t, "value5_fromkvs2", v)
}

func TestStoreReduceSize(t *testing.T) {
	tmpf, err := os.CreateTemp("", "lfstest3")
	assert.Nil(t, err)
	filename := tmpf.Name()
	defer os.Remove(filename)
	tmpf.Close()

	kvs, err := NewStore(filename)
	assert.Nil(t, err)

	kvs.Set("key1", "I woke up in a Soho doorway")
	kvs.Set("key2", "A policeman knew my name")
	kvs.Set("key3", "He said 'You can go sleep at home tonight")
	kvs.Set("key4", "If you can get up and walk away'")

	assert.NotNil(t, kvs.Get("key1"))
	assert.NotNil(t, kvs.Get("key2"))
	assert.NotNil(t, kvs.Get("key3"))
	assert.NotNil(t, kvs.Get("key4"))

	assert.Nil(t, kvs.Save())

	stat1, _ := os.Stat(filename)

	// Remove all but 1 key & save smaller version
	kvs.Remove("key2")
	kvs.Remove("key3")
	kvs.Remove("key4")
	assert.Nil(t, kvs.Save())

	// Now reload fresh & prove works
	kvs = nil

	kvs, err = NewStore(filename)
	assert.Nil(t, err)
	assert.NotNil(t, kvs.Get("key1"))
	assert.Nil(t, kvs.Get("key2"))
	assert.Nil(t, kvs.Get("key3"))
	assert.Nil(t, kvs.Get("key4"))

	stat2, _ := os.Stat(filename)

	assert.True(t, stat2.Size() < stat1.Size(), "Size should have reduced, was %d now %d", stat1.Size(), stat2.Size())

}