github.com/moby/docker@v26.1.3+incompatible/libnetwork/datastore/datastore_test.go (about) 1 package datastore 2 3 import ( 4 "encoding/json" 5 "testing" 6 7 "github.com/docker/docker/libnetwork/options" 8 "gotest.tools/v3/assert" 9 is "gotest.tools/v3/assert/cmp" 10 ) 11 12 const dummyKey = "dummy" 13 14 // NewTestDataStore can be used by other Tests in order to use custom datastore 15 func NewTestDataStore() *Store { 16 s := NewMockStore() 17 return &Store{store: s, cache: newCache(s)} 18 } 19 20 func TestKey(t *testing.T) { 21 sKey := Key("hello", "world") 22 const expected = "docker/network/v1.0/hello/world/" 23 assert.Check(t, is.Equal(sKey, expected)) 24 } 25 26 func TestInvalidDataStore(t *testing.T) { 27 _, err := New(ScopeCfg{ 28 Client: ScopeClientCfg{ 29 Provider: "invalid", 30 Address: "localhost:8500", 31 }, 32 }) 33 assert.Check(t, is.Error(err, "unsupported KV store")) 34 } 35 36 func TestKVObjectFlatKey(t *testing.T) { 37 store := NewTestDataStore() 38 expected := dummyKVObject("1000", true) 39 err := store.PutObjectAtomic(expected) 40 assert.Check(t, err) 41 42 n := dummyObject{ID: "1000"} // GetObject uses KVObject.Key() for cache lookup. 43 err = store.GetObject(&n) 44 assert.Check(t, err) 45 assert.Check(t, is.Equal(n.Name, expected.Name)) 46 } 47 48 func TestAtomicKVObjectFlatKey(t *testing.T) { 49 store := NewTestDataStore() 50 expected := dummyKVObject("1111", true) 51 assert.Check(t, !expected.Exists()) 52 err := store.PutObjectAtomic(expected) 53 assert.Check(t, err) 54 assert.Check(t, expected.Exists()) 55 56 // PutObjectAtomic automatically sets the Index again. Hence the following must pass. 57 58 err = store.PutObjectAtomic(expected) 59 assert.Check(t, err, "Atomic update should succeed.") 60 61 // Get the latest index and try PutObjectAtomic again for the same Key 62 // This must succeed as well 63 n := dummyObject{ID: "1111"} // GetObject uses KVObject.Key() for cache lookup. 64 err = store.GetObject(&n) 65 assert.Check(t, err) 66 n.ReturnValue = true 67 err = store.PutObjectAtomic(&n) 68 assert.Check(t, err) 69 70 // Get the Object using GetObject, then set again. 71 newObj := dummyObject{ID: "1111"} // GetObject uses KVObject.Key() for cache lookup. 72 err = store.GetObject(&newObj) 73 assert.Check(t, err) 74 assert.Check(t, newObj.Exists()) 75 err = store.PutObjectAtomic(&n) 76 assert.Check(t, err) 77 } 78 79 // dummy data used to test the datastore 80 type dummyObject struct { 81 Name string `kv:"leaf"` 82 NetworkType string `kv:"leaf"` 83 EnableIPv6 bool `kv:"leaf"` 84 Rec *recStruct `kv:"recursive"` 85 Dict map[string]*recStruct `kv:"iterative"` 86 Generic options.Generic `kv:"iterative"` 87 ID string 88 DBIndex uint64 89 DBExists bool 90 SkipSave bool 91 ReturnValue bool 92 } 93 94 func (n *dummyObject) Key() []string { 95 return []string{dummyKey, n.ID} 96 } 97 98 func (n *dummyObject) KeyPrefix() []string { 99 return []string{dummyKey} 100 } 101 102 func (n *dummyObject) Value() []byte { 103 if !n.ReturnValue { 104 return nil 105 } 106 107 b, err := json.Marshal(n) 108 if err != nil { 109 return nil 110 } 111 return b 112 } 113 114 func (n *dummyObject) SetValue(value []byte) error { 115 return json.Unmarshal(value, n) 116 } 117 118 func (n *dummyObject) Index() uint64 { 119 return n.DBIndex 120 } 121 122 func (n *dummyObject) SetIndex(index uint64) { 123 n.DBIndex = index 124 n.DBExists = true 125 } 126 127 func (n *dummyObject) Exists() bool { 128 return n.DBExists 129 } 130 131 func (n *dummyObject) Skip() bool { 132 return n.SkipSave 133 } 134 135 func (n *dummyObject) MarshalJSON() ([]byte, error) { 136 return json.Marshal(map[string]interface{}{ 137 "name": n.Name, 138 "networkType": n.NetworkType, 139 "enableIPv6": n.EnableIPv6, 140 "generic": n.Generic, 141 }) 142 } 143 144 func (n *dummyObject) UnmarshalJSON(b []byte) error { 145 var netMap map[string]interface{} 146 if err := json.Unmarshal(b, &netMap); err != nil { 147 return err 148 } 149 n.Name = netMap["name"].(string) 150 n.NetworkType = netMap["networkType"].(string) 151 n.EnableIPv6 = netMap["enableIPv6"].(bool) 152 n.Generic = netMap["generic"].(map[string]interface{}) 153 return nil 154 } 155 156 func (n *dummyObject) New() KVObject { 157 return &dummyObject{} 158 } 159 160 func (n *dummyObject) CopyTo(o KVObject) error { 161 if err := o.SetValue(n.Value()); err != nil { 162 return err 163 } 164 o.SetIndex(n.Index()) 165 return nil 166 } 167 168 // dummy structure to test "recursive" cases 169 type recStruct struct { 170 Name string `kv:"leaf"` 171 Field1 int `kv:"leaf"` 172 Dict map[string]string `kv:"iterative"` 173 DBIndex uint64 174 DBExists bool 175 SkipSave bool 176 } 177 178 func (r *recStruct) Key() []string { 179 return []string{"recStruct"} 180 } 181 182 func (r *recStruct) Value() []byte { 183 b, err := json.Marshal(r) 184 if err != nil { 185 return nil 186 } 187 return b 188 } 189 190 func (r *recStruct) SetValue(value []byte) error { 191 return json.Unmarshal(value, r) 192 } 193 194 func (r *recStruct) Index() uint64 { 195 return r.DBIndex 196 } 197 198 func (r *recStruct) SetIndex(index uint64) { 199 r.DBIndex = index 200 r.DBExists = true 201 } 202 203 func (r *recStruct) Exists() bool { 204 return r.DBExists 205 } 206 207 func (r *recStruct) Skip() bool { 208 return r.SkipSave 209 } 210 211 func dummyKVObject(id string, retValue bool) *dummyObject { 212 cDict := map[string]string{ 213 "foo": "bar", 214 "hello": "world", 215 } 216 return &dummyObject{ 217 Name: "testNw", 218 NetworkType: "bridge", 219 EnableIPv6: true, 220 Rec: &recStruct{Name: "gen", Field1: 5, Dict: cDict}, 221 ID: id, 222 DBIndex: 0, 223 ReturnValue: retValue, 224 DBExists: false, 225 SkipSave: false, 226 Generic: map[string]interface{}{ 227 "label1": &recStruct{Name: "value1", Field1: 1, Dict: cDict}, 228 "label2": "subnet=10.1.1.0/16", 229 }, 230 } 231 }