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