github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/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 "gotest.tools/v3/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.Fatal("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.Check(t, !expected.Exists()) 72 err := store.PutObjectAtomic(expected) 73 if err != nil { 74 t.Fatal(err) 75 } 76 assert.Check(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 if err != nil { 105 t.Fatal(err) 106 } 107 assert.Check(t, newObj.Exists()) 108 err = store.PutObjectAtomic(&n) 109 if err != nil { 110 t.Fatal(err) 111 } 112 113 } 114 115 // dummy data used to test the datastore 116 type dummyObject struct { 117 Name string `kv:"leaf"` 118 NetworkType string `kv:"leaf"` 119 EnableIPv6 bool `kv:"leaf"` 120 Rec *recStruct `kv:"recursive"` 121 Dict map[string]*recStruct `kv:"iterative"` 122 Generic options.Generic `kv:"iterative"` 123 ID string 124 DBIndex uint64 125 DBExists bool 126 SkipSave bool 127 ReturnValue bool 128 } 129 130 func (n *dummyObject) Key() []string { 131 return []string{dummyKey, n.ID} 132 } 133 134 func (n *dummyObject) KeyPrefix() []string { 135 return []string{dummyKey} 136 } 137 138 func (n *dummyObject) Value() []byte { 139 if !n.ReturnValue { 140 return nil 141 } 142 143 b, err := json.Marshal(n) 144 if err != nil { 145 return nil 146 } 147 return b 148 } 149 150 func (n *dummyObject) SetValue(value []byte) error { 151 return json.Unmarshal(value, n) 152 } 153 154 func (n *dummyObject) Index() uint64 { 155 return n.DBIndex 156 } 157 158 func (n *dummyObject) SetIndex(index uint64) { 159 n.DBIndex = index 160 n.DBExists = true 161 } 162 163 func (n *dummyObject) Exists() bool { 164 return n.DBExists 165 } 166 167 func (n *dummyObject) Skip() bool { 168 return n.SkipSave 169 } 170 171 func (n *dummyObject) DataScope() string { 172 return LocalScope 173 } 174 175 func (n *dummyObject) MarshalJSON() ([]byte, error) { 176 netMap := make(map[string]interface{}) 177 netMap["name"] = n.Name 178 netMap["networkType"] = n.NetworkType 179 netMap["enableIPv6"] = n.EnableIPv6 180 netMap["generic"] = n.Generic 181 return json.Marshal(netMap) 182 } 183 184 func (n *dummyObject) UnmarshalJSON(b []byte) (err error) { 185 var netMap map[string]interface{} 186 if err := json.Unmarshal(b, &netMap); err != nil { 187 return err 188 } 189 n.Name = netMap["name"].(string) 190 n.NetworkType = netMap["networkType"].(string) 191 n.EnableIPv6 = netMap["enableIPv6"].(bool) 192 n.Generic = netMap["generic"].(map[string]interface{}) 193 return nil 194 } 195 196 // dummy structure to test "recursive" cases 197 type recStruct struct { 198 Name string `kv:"leaf"` 199 Field1 int `kv:"leaf"` 200 Dict map[string]string `kv:"iterative"` 201 DBIndex uint64 202 DBExists bool 203 SkipSave bool 204 } 205 206 func (r *recStruct) Key() []string { 207 return []string{"recStruct"} 208 } 209 func (r *recStruct) Value() []byte { 210 b, err := json.Marshal(r) 211 if err != nil { 212 return nil 213 } 214 return b 215 } 216 217 func (r *recStruct) SetValue(value []byte) error { 218 return json.Unmarshal(value, r) 219 } 220 221 func (r *recStruct) Index() uint64 { 222 return r.DBIndex 223 } 224 225 func (r *recStruct) SetIndex(index uint64) { 226 r.DBIndex = index 227 r.DBExists = true 228 } 229 230 func (r *recStruct) Exists() bool { 231 return r.DBExists 232 } 233 234 func (r *recStruct) Skip() bool { 235 return r.SkipSave 236 } 237 238 func dummyKVObject(id string, retValue bool) *dummyObject { 239 cDict := make(map[string]string) 240 cDict["foo"] = "bar" 241 cDict["hello"] = "world" 242 n := dummyObject{ 243 Name: "testNw", 244 NetworkType: "bridge", 245 EnableIPv6: true, 246 Rec: &recStruct{"gen", 5, cDict, 0, false, false}, 247 ID: id, 248 DBIndex: 0, 249 ReturnValue: retValue, 250 DBExists: false, 251 SkipSave: false} 252 generic := make(map[string]interface{}) 253 generic["label1"] = &recStruct{"value1", 1, cDict, 0, false, false} 254 generic["label2"] = "subnet=10.1.1.0/16" 255 n.Generic = generic 256 return &n 257 }