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  }