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