github.com/uber/kraken@v0.1.4/tracker/originstore/store_test.go (about)

     1  // Copyright (c) 2016-2019 Uber Technologies, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  package originstore
    15  
    16  import (
    17  	"errors"
    18  	"testing"
    19  	"time"
    20  
    21  	"github.com/uber/kraken/core"
    22  	"github.com/uber/kraken/lib/hostlist"
    23  	"github.com/uber/kraken/mocks/origin/blobclient"
    24  	"github.com/uber/kraken/utils/testutil"
    25  
    26  	"github.com/andres-erbsen/clock"
    27  	"github.com/golang/mock/gomock"
    28  	"github.com/stretchr/testify/require"
    29  )
    30  
    31  const _testDNS = "test-origin-cluster-dns:80"
    32  
    33  type storeMocks struct {
    34  	ctrl     *gomock.Controller
    35  	provider *mockblobclient.MockProvider
    36  }
    37  
    38  func newStoreMocks(t *testing.T) (*storeMocks, func()) {
    39  	cleanup := &testutil.Cleanup{}
    40  
    41  	ctrl := gomock.NewController(t)
    42  	cleanup.Add(ctrl.Finish)
    43  
    44  	provider := mockblobclient.NewMockProvider(ctrl)
    45  
    46  	return &storeMocks{ctrl, provider}, cleanup.Run
    47  }
    48  
    49  func (m *storeMocks) new(config Config, clk clock.Clock) Store {
    50  	return New(config, clk, hostlist.Fixture(_testDNS), m.provider)
    51  }
    52  
    53  func (m *storeMocks) expectClient(addr string) *mockblobclient.MockClient {
    54  	client := mockblobclient.NewMockClient(m.ctrl)
    55  	m.provider.EXPECT().Provide(addr).Return(client)
    56  	return client
    57  }
    58  
    59  func originViews(n int) (octxs []core.PeerContext, addrs []string, pinfos []*core.PeerInfo) {
    60  	for i := 0; i < n; i++ {
    61  		octx := core.OriginContextFixture()
    62  		octxs = append(octxs, octx)
    63  		addrs = append(addrs, octx.IP)
    64  		pinfos = append(pinfos, core.PeerInfoFromContext(octx, true))
    65  	}
    66  	return
    67  }
    68  
    69  func TestStoreGetOrigins(t *testing.T) {
    70  	require := require.New(t)
    71  
    72  	mocks, cleanup := newStoreMocks(t)
    73  	defer cleanup()
    74  
    75  	store := mocks.new(Config{}, clock.New())
    76  
    77  	d := core.DigestFixture()
    78  	octxs, addrs, pinfos := originViews(3)
    79  
    80  	dnsClient := mocks.expectClient(_testDNS)
    81  	dnsClient.EXPECT().Locations(d).Return(addrs, nil)
    82  
    83  	for _, octx := range octxs {
    84  		client := mocks.expectClient(octx.IP)
    85  		client.EXPECT().GetPeerContext().Return(octx, nil)
    86  	}
    87  
    88  	// Ensure caching.
    89  	for i := 0; i < 100; i++ {
    90  		result, err := store.GetOrigins(d)
    91  		require.NoError(err)
    92  		require.Equal(pinfos, result)
    93  	}
    94  }
    95  
    96  func TestStoreGetOriginsResilientToUnavailableOrigins(t *testing.T) {
    97  	require := require.New(t)
    98  
    99  	mocks, cleanup := newStoreMocks(t)
   100  	defer cleanup()
   101  
   102  	store := mocks.new(Config{}, clock.New())
   103  
   104  	d := core.DigestFixture()
   105  	octxs, addrs, pinfos := originViews(3)
   106  
   107  	dnsClient := mocks.expectClient(_testDNS)
   108  	dnsClient.EXPECT().Locations(d).Return(addrs, nil)
   109  
   110  	// Only one origin available.
   111  	available := 1
   112  	for i, octx := range octxs {
   113  		client := mocks.expectClient(octx.IP)
   114  		if i < available {
   115  			client.EXPECT().GetPeerContext().Return(octx, nil)
   116  		} else {
   117  			client.EXPECT().GetPeerContext().Return(core.PeerContext{}, errors.New("some error"))
   118  		}
   119  	}
   120  
   121  	// Ensure caching.
   122  	for i := 0; i < 100; i++ {
   123  		result, err := store.GetOrigins(d)
   124  		require.NoError(err)
   125  		require.Equal(pinfos[:available], result)
   126  	}
   127  }
   128  
   129  func TestStoreGetOriginsErrorOnAllUnavailable(t *testing.T) {
   130  	require := require.New(t)
   131  
   132  	mocks, cleanup := newStoreMocks(t)
   133  	defer cleanup()
   134  
   135  	store := mocks.new(Config{}, clock.New())
   136  
   137  	d := core.DigestFixture()
   138  	octxs, addrs, _ := originViews(3)
   139  
   140  	dnsClient := mocks.expectClient(_testDNS)
   141  	dnsClient.EXPECT().Locations(d).Return(addrs, nil)
   142  
   143  	for _, octx := range octxs {
   144  		client := mocks.expectClient(octx.IP)
   145  		client.EXPECT().GetPeerContext().Return(core.PeerContext{}, errors.New("some error"))
   146  	}
   147  
   148  	// Ensure caching.
   149  	for i := 0; i < 100; i++ {
   150  		_, err := store.GetOrigins(d)
   151  		require.Error(err)
   152  		_, ok := err.(allUnavailableError)
   153  		require.True(ok)
   154  	}
   155  }
   156  
   157  func TestStoreGetOriginsErrorTTL(t *testing.T) {
   158  	require := require.New(t)
   159  
   160  	mocks, cleanup := newStoreMocks(t)
   161  	defer cleanup()
   162  
   163  	clk := clock.NewMock()
   164  	config := Config{
   165  		LocationsTTL:         time.Minute,
   166  		OriginUnavailableTTL: 30 * time.Second,
   167  	}
   168  
   169  	store := mocks.new(config, clk)
   170  
   171  	d := core.DigestFixture()
   172  	octxs, addrs, pinfos := originViews(3)
   173  
   174  	dnsClient := mocks.expectClient(_testDNS)
   175  	dnsClient.EXPECT().Locations(d).Return(addrs, nil)
   176  
   177  	for _, octx := range octxs {
   178  		client := mocks.expectClient(octx.IP)
   179  		client.EXPECT().GetPeerContext().Return(core.PeerContext{}, errors.New("some error"))
   180  	}
   181  
   182  	for i := 0; i < 100; i++ {
   183  		_, err := store.GetOrigins(d)
   184  		require.Error(err)
   185  		_, ok := err.(allUnavailableError)
   186  		require.True(ok)
   187  	}
   188  
   189  	// Errors should be cleared now.
   190  	clk.Add(config.OriginUnavailableTTL + 1)
   191  
   192  	for _, octx := range octxs {
   193  		client := mocks.expectClient(octx.IP)
   194  		client.EXPECT().GetPeerContext().Return(octx, nil)
   195  	}
   196  
   197  	for i := 0; i < 100; i++ {
   198  		result, err := store.GetOrigins(d)
   199  		require.NoError(err)
   200  		require.Equal(pinfos, result)
   201  	}
   202  }
   203  
   204  func TestStoreGetOriginsCacheTTL(t *testing.T) {
   205  	require := require.New(t)
   206  
   207  	mocks, cleanup := newStoreMocks(t)
   208  	defer cleanup()
   209  
   210  	clk := clock.NewMock()
   211  	config := Config{
   212  		LocationsTTL:     time.Minute,
   213  		OriginContextTTL: 30 * time.Second,
   214  	}
   215  
   216  	store := mocks.new(config, clk)
   217  
   218  	d := core.DigestFixture()
   219  	octxs, addrs, pinfos := originViews(3)
   220  
   221  	dnsClient := mocks.expectClient(_testDNS)
   222  	dnsClient.EXPECT().Locations(d).Return(addrs, nil)
   223  
   224  	for _, octx := range octxs {
   225  		client := mocks.expectClient(octx.IP)
   226  		client.EXPECT().GetPeerContext().Return(octx, nil)
   227  	}
   228  
   229  	for i := 0; i < 100; i++ {
   230  		result, err := store.GetOrigins(d)
   231  		require.NoError(err)
   232  		require.Equal(pinfos, result)
   233  	}
   234  
   235  	// Cached contexts should be cleared now.
   236  	clk.Add(config.OriginContextTTL + 1)
   237  
   238  	for _, octx := range octxs {
   239  		client := mocks.expectClient(octx.IP)
   240  		client.EXPECT().GetPeerContext().Return(core.PeerContext{}, errors.New("some error"))
   241  	}
   242  
   243  	for i := 0; i < 100; i++ {
   244  		_, err := store.GetOrigins(d)
   245  		require.Error(err)
   246  		_, ok := err.(allUnavailableError)
   247  		require.True(ok)
   248  	}
   249  
   250  }