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 }