github.com/ttys3/engine@v17.12.1-ce-rc2+incompatible/pkg/discovery/kv/kv_test.go (about) 1 package kv 2 3 import ( 4 "errors" 5 "io/ioutil" 6 "os" 7 "path" 8 "testing" 9 "time" 10 11 "github.com/docker/docker/pkg/discovery" 12 "github.com/docker/libkv" 13 "github.com/docker/libkv/store" 14 "github.com/go-check/check" 15 ) 16 17 // Hook up gocheck into the "go test" runner. 18 func Test(t *testing.T) { check.TestingT(t) } 19 20 type DiscoverySuite struct{} 21 22 var _ = check.Suite(&DiscoverySuite{}) 23 24 func (ds *DiscoverySuite) TestInitialize(c *check.C) { 25 storeMock := &FakeStore{ 26 Endpoints: []string{"127.0.0.1"}, 27 } 28 d := &Discovery{backend: store.CONSUL} 29 d.Initialize("127.0.0.1", 0, 0, nil) 30 d.store = storeMock 31 32 s := d.store.(*FakeStore) 33 c.Assert(s.Endpoints, check.HasLen, 1) 34 c.Assert(s.Endpoints[0], check.Equals, "127.0.0.1") 35 c.Assert(d.path, check.Equals, defaultDiscoveryPath) 36 37 storeMock = &FakeStore{ 38 Endpoints: []string{"127.0.0.1:1234"}, 39 } 40 d = &Discovery{backend: store.CONSUL} 41 d.Initialize("127.0.0.1:1234/path", 0, 0, nil) 42 d.store = storeMock 43 44 s = d.store.(*FakeStore) 45 c.Assert(s.Endpoints, check.HasLen, 1) 46 c.Assert(s.Endpoints[0], check.Equals, "127.0.0.1:1234") 47 c.Assert(d.path, check.Equals, "path/"+defaultDiscoveryPath) 48 49 storeMock = &FakeStore{ 50 Endpoints: []string{"127.0.0.1:1234", "127.0.0.2:1234", "127.0.0.3:1234"}, 51 } 52 d = &Discovery{backend: store.CONSUL} 53 d.Initialize("127.0.0.1:1234,127.0.0.2:1234,127.0.0.3:1234/path", 0, 0, nil) 54 d.store = storeMock 55 56 s = d.store.(*FakeStore) 57 c.Assert(s.Endpoints, check.HasLen, 3) 58 c.Assert(s.Endpoints[0], check.Equals, "127.0.0.1:1234") 59 c.Assert(s.Endpoints[1], check.Equals, "127.0.0.2:1234") 60 c.Assert(s.Endpoints[2], check.Equals, "127.0.0.3:1234") 61 62 c.Assert(d.path, check.Equals, "path/"+defaultDiscoveryPath) 63 } 64 65 // Extremely limited mock store so we can test initialization 66 type Mock struct { 67 // Endpoints passed to InitializeMock 68 Endpoints []string 69 70 // Options passed to InitializeMock 71 Options *store.Config 72 } 73 74 func NewMock(endpoints []string, options *store.Config) (store.Store, error) { 75 s := &Mock{} 76 s.Endpoints = endpoints 77 s.Options = options 78 return s, nil 79 } 80 func (s *Mock) Put(key string, value []byte, opts *store.WriteOptions) error { 81 return errors.New("Put not supported") 82 } 83 func (s *Mock) Get(key string) (*store.KVPair, error) { 84 return nil, errors.New("Get not supported") 85 } 86 func (s *Mock) Delete(key string) error { 87 return errors.New("Delete not supported") 88 } 89 90 // Exists mock 91 func (s *Mock) Exists(key string) (bool, error) { 92 return false, errors.New("Exists not supported") 93 } 94 95 // Watch mock 96 func (s *Mock) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair, error) { 97 return nil, errors.New("Watch not supported") 98 } 99 100 // WatchTree mock 101 func (s *Mock) WatchTree(prefix string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) { 102 return nil, errors.New("WatchTree not supported") 103 } 104 105 // NewLock mock 106 func (s *Mock) NewLock(key string, options *store.LockOptions) (store.Locker, error) { 107 return nil, errors.New("NewLock not supported") 108 } 109 110 // List mock 111 func (s *Mock) List(prefix string) ([]*store.KVPair, error) { 112 return nil, errors.New("List not supported") 113 } 114 115 // DeleteTree mock 116 func (s *Mock) DeleteTree(prefix string) error { 117 return errors.New("DeleteTree not supported") 118 } 119 120 // AtomicPut mock 121 func (s *Mock) AtomicPut(key string, value []byte, previous *store.KVPair, opts *store.WriteOptions) (bool, *store.KVPair, error) { 122 return false, nil, errors.New("AtomicPut not supported") 123 } 124 125 // AtomicDelete mock 126 func (s *Mock) AtomicDelete(key string, previous *store.KVPair) (bool, error) { 127 return false, errors.New("AtomicDelete not supported") 128 } 129 130 // Close mock 131 func (s *Mock) Close() { 132 } 133 134 func (ds *DiscoverySuite) TestInitializeWithCerts(c *check.C) { 135 cert := `-----BEGIN CERTIFICATE----- 136 MIIDCDCCAfKgAwIBAgIICifG7YeiQOEwCwYJKoZIhvcNAQELMBIxEDAOBgNVBAMT 137 B1Rlc3QgQ0EwHhcNMTUxMDAxMjMwMDAwWhcNMjAwOTI5MjMwMDAwWjASMRAwDgYD 138 VQQDEwdUZXN0IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1wRC 139 O+flnLTK5ImjTurNRHwSejuqGbc4CAvpB0hS+z0QlSs4+zE9h80aC4hz+6caRpds 140 +J908Q+RvAittMHbpc7VjbZP72G6fiXk7yPPl6C10HhRSoSi3nY+B7F2E8cuz14q 141 V2e+ejhWhSrBb/keyXpcyjoW1BOAAJ2TIclRRkICSCZrpXUyXxAvzXfpFXo1RhSb 142 UywN11pfiCQzDUN7sPww9UzFHuAHZHoyfTr27XnJYVUerVYrCPq8vqfn//01qz55 143 Xs0hvzGdlTFXhuabFtQnKFH5SNwo/fcznhB7rePOwHojxOpXTBepUCIJLbtNnWFT 144 V44t9gh5IqIWtoBReQIDAQABo2YwZDAOBgNVHQ8BAf8EBAMCAAYwEgYDVR0TAQH/ 145 BAgwBgEB/wIBAjAdBgNVHQ4EFgQUZKUI8IIjIww7X/6hvwggQK4bD24wHwYDVR0j 146 BBgwFoAUZKUI8IIjIww7X/6hvwggQK4bD24wCwYJKoZIhvcNAQELA4IBAQDES2cz 147 7sCQfDCxCIWH7X8kpi/JWExzUyQEJ0rBzN1m3/x8ySRxtXyGekimBqQwQdFqlwMI 148 xzAQKkh3ue8tNSzRbwqMSyH14N1KrSxYS9e9szJHfUasoTpQGPmDmGIoRJuq1h6M 149 ej5x1SCJ7GWCR6xEXKUIE9OftXm9TdFzWa7Ja3OHz/mXteii8VXDuZ5ACq6EE5bY 150 8sP4gcICfJ5fTrpTlk9FIqEWWQrCGa5wk95PGEj+GJpNogjXQ97wVoo/Y3p1brEn 151 t5zjN9PAq4H1fuCMdNNA+p1DHNwd+ELTxcMAnb2ajwHvV6lKPXutrTFc4umJToBX 152 FpTxDmJHEV4bzUzh 153 -----END CERTIFICATE----- 154 ` 155 key := `-----BEGIN RSA PRIVATE KEY----- 156 MIIEpQIBAAKCAQEA1wRCO+flnLTK5ImjTurNRHwSejuqGbc4CAvpB0hS+z0QlSs4 157 +zE9h80aC4hz+6caRpds+J908Q+RvAittMHbpc7VjbZP72G6fiXk7yPPl6C10HhR 158 SoSi3nY+B7F2E8cuz14qV2e+ejhWhSrBb/keyXpcyjoW1BOAAJ2TIclRRkICSCZr 159 pXUyXxAvzXfpFXo1RhSbUywN11pfiCQzDUN7sPww9UzFHuAHZHoyfTr27XnJYVUe 160 rVYrCPq8vqfn//01qz55Xs0hvzGdlTFXhuabFtQnKFH5SNwo/fcznhB7rePOwHoj 161 xOpXTBepUCIJLbtNnWFTV44t9gh5IqIWtoBReQIDAQABAoIBAHSWipORGp/uKFXj 162 i/mut776x8ofsAxhnLBARQr93ID+i49W8H7EJGkOfaDjTICYC1dbpGrri61qk8sx 163 qX7p3v/5NzKwOIfEpirgwVIqSNYe/ncbxnhxkx6tXtUtFKmEx40JskvSpSYAhmmO 164 1XSx0E/PWaEN/nLgX/f1eWJIlxlQkk3QeqL+FGbCXI48DEtlJ9+MzMu4pAwZTpj5 165 5qtXo5JJ0jRGfJVPAOznRsYqv864AhMdMIWguzk6EGnbaCWwPcfcn+h9a5LMdony 166 MDHfBS7bb5tkF3+AfnVY3IBMVx7YlsD9eAyajlgiKu4zLbwTRHjXgShy+4Oussz0 167 ugNGnkECgYEA/hi+McrZC8C4gg6XqK8+9joD8tnyDZDz88BQB7CZqABUSwvjDqlP 168 L8hcwo/lzvjBNYGkqaFPUICGWKjeCtd8pPS2DCVXxDQX4aHF1vUur0uYNncJiV3N 169 XQz4Iemsa6wnKf6M67b5vMXICw7dw0HZCdIHD1hnhdtDz0uVpeevLZ8CgYEA2KCT 170 Y43lorjrbCgMqtlefkr3GJA9dey+hTzCiWEOOqn9RqGoEGUday0sKhiLofOgmN2B 171 LEukpKIey8s+Q/cb6lReajDVPDsMweX8i7hz3Wa4Ugp4Xa5BpHqu8qIAE2JUZ7bU 172 t88aQAYE58pUF+/Lq1QzAQdrjjzQBx6SrBxieecCgYEAvukoPZEC8mmiN1VvbTX+ 173 QFHmlZha3QaDxChB+QUe7bMRojEUL/fVnzkTOLuVFqSfxevaI/km9n0ac5KtAchV 174 xjp2bTnBb5EUQFqjopYktWA+xO07JRJtMfSEmjZPbbay1kKC7rdTfBm961EIHaRj 175 xZUf6M+rOE8964oGrdgdLlECgYEA046GQmx6fh7/82FtdZDRQp9tj3SWQUtSiQZc 176 qhO59Lq8mjUXz+MgBuJXxkiwXRpzlbaFB0Bca1fUoYw8o915SrDYf/Zu2OKGQ/qa 177 V81sgiVmDuEgycR7YOlbX6OsVUHrUlpwhY3hgfMe6UtkMvhBvHF/WhroBEIJm1pV 178 PXZ/CbMCgYEApNWVktFBjOaYfY6SNn4iSts1jgsQbbpglg3kT7PLKjCAhI6lNsbk 179 dyT7ut01PL6RaW4SeQWtrJIVQaM6vF3pprMKqlc5XihOGAmVqH7rQx9rtQB5TicL 180 BFrwkQE4HQtQBV60hYQUzzlSk44VFDz+jxIEtacRHaomDRh2FtOTz+I= 181 -----END RSA PRIVATE KEY----- 182 ` 183 certFile, err := ioutil.TempFile("", "cert") 184 c.Assert(err, check.IsNil) 185 defer os.Remove(certFile.Name()) 186 certFile.Write([]byte(cert)) 187 certFile.Close() 188 keyFile, err := ioutil.TempFile("", "key") 189 c.Assert(err, check.IsNil) 190 defer os.Remove(keyFile.Name()) 191 keyFile.Write([]byte(key)) 192 keyFile.Close() 193 194 libkv.AddStore("mock", NewMock) 195 d := &Discovery{backend: "mock"} 196 err = d.Initialize("127.0.0.3:1234", 0, 0, map[string]string{ 197 "kv.cacertfile": certFile.Name(), 198 "kv.certfile": certFile.Name(), 199 "kv.keyfile": keyFile.Name(), 200 }) 201 c.Assert(err, check.IsNil) 202 s := d.store.(*Mock) 203 c.Assert(s.Options.TLS, check.NotNil) 204 c.Assert(s.Options.TLS.RootCAs, check.NotNil) 205 c.Assert(s.Options.TLS.Certificates, check.HasLen, 1) 206 } 207 208 func (ds *DiscoverySuite) TestWatch(c *check.C) { 209 mockCh := make(chan []*store.KVPair) 210 211 storeMock := &FakeStore{ 212 Endpoints: []string{"127.0.0.1:1234"}, 213 mockKVChan: mockCh, 214 } 215 216 d := &Discovery{backend: store.CONSUL} 217 d.Initialize("127.0.0.1:1234/path", 0, 0, nil) 218 d.store = storeMock 219 220 expected := discovery.Entries{ 221 &discovery.Entry{Host: "1.1.1.1", Port: "1111"}, 222 &discovery.Entry{Host: "2.2.2.2", Port: "2222"}, 223 } 224 kvs := []*store.KVPair{ 225 {Key: path.Join("path", defaultDiscoveryPath, "1.1.1.1"), Value: []byte("1.1.1.1:1111")}, 226 {Key: path.Join("path", defaultDiscoveryPath, "2.2.2.2"), Value: []byte("2.2.2.2:2222")}, 227 } 228 229 stopCh := make(chan struct{}) 230 ch, errCh := d.Watch(stopCh) 231 232 // It should fire an error since the first WatchTree call failed. 233 c.Assert(<-errCh, check.ErrorMatches, "test error") 234 // We have to drain the error channel otherwise Watch will get stuck. 235 go func() { 236 for range errCh { 237 } 238 }() 239 240 // Push the entries into the store channel and make sure discovery emits. 241 mockCh <- kvs 242 c.Assert(<-ch, check.DeepEquals, expected) 243 244 // Add a new entry. 245 expected = append(expected, &discovery.Entry{Host: "3.3.3.3", Port: "3333"}) 246 kvs = append(kvs, &store.KVPair{Key: path.Join("path", defaultDiscoveryPath, "3.3.3.3"), Value: []byte("3.3.3.3:3333")}) 247 mockCh <- kvs 248 c.Assert(<-ch, check.DeepEquals, expected) 249 250 close(mockCh) 251 // Give it enough time to call WatchTree. 252 time.Sleep(3 * time.Second) 253 254 // Stop and make sure it closes all channels. 255 close(stopCh) 256 c.Assert(<-ch, check.IsNil) 257 c.Assert(<-errCh, check.IsNil) 258 } 259 260 // FakeStore implements store.Store methods. It mocks all store 261 // function in a simple, naive way. 262 type FakeStore struct { 263 Endpoints []string 264 Options *store.Config 265 mockKVChan <-chan []*store.KVPair 266 267 watchTreeCallCount int 268 } 269 270 func (s *FakeStore) Put(key string, value []byte, options *store.WriteOptions) error { 271 return nil 272 } 273 274 func (s *FakeStore) Get(key string) (*store.KVPair, error) { 275 return nil, nil 276 } 277 278 func (s *FakeStore) Delete(key string) error { 279 return nil 280 } 281 282 func (s *FakeStore) Exists(key string) (bool, error) { 283 return true, nil 284 } 285 286 func (s *FakeStore) Watch(key string, stopCh <-chan struct{}) (<-chan *store.KVPair, error) { 287 return nil, nil 288 } 289 290 // WatchTree will fail the first time, and return the mockKVchan afterwards. 291 // This is the behavior we need for testing.. If we need 'moar', should update this. 292 func (s *FakeStore) WatchTree(directory string, stopCh <-chan struct{}) (<-chan []*store.KVPair, error) { 293 if s.watchTreeCallCount == 0 { 294 s.watchTreeCallCount = 1 295 return nil, errors.New("test error") 296 } 297 // First calls error 298 return s.mockKVChan, nil 299 } 300 301 func (s *FakeStore) NewLock(key string, options *store.LockOptions) (store.Locker, error) { 302 return nil, nil 303 } 304 305 func (s *FakeStore) List(directory string) ([]*store.KVPair, error) { 306 return []*store.KVPair{}, nil 307 } 308 309 func (s *FakeStore) DeleteTree(directory string) error { 310 return nil 311 } 312 313 func (s *FakeStore) AtomicPut(key string, value []byte, previous *store.KVPair, options *store.WriteOptions) (bool, *store.KVPair, error) { 314 return true, nil, nil 315 } 316 317 func (s *FakeStore) AtomicDelete(key string, previous *store.KVPair) (bool, error) { 318 return true, nil 319 } 320 321 func (s *FakeStore) Close() { 322 }