github.com/ethersphere/bee/v2@v2.2.0/pkg/resolver/multiresolver/multiresolver_test.go (about) 1 // Copyright 2020 The Swarm Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package multiresolver_test 6 7 import ( 8 "errors" 9 "fmt" 10 "reflect" 11 "testing" 12 13 "github.com/ethersphere/bee/v2/pkg/log" 14 "github.com/ethersphere/bee/v2/pkg/resolver" 15 "github.com/ethersphere/bee/v2/pkg/resolver/mock" 16 "github.com/ethersphere/bee/v2/pkg/resolver/multiresolver" 17 "github.com/ethersphere/bee/v2/pkg/swarm" 18 ) 19 20 type Address = swarm.Address 21 22 func newAddr(s string) Address { 23 return swarm.NewAddress([]byte(s)) 24 } 25 26 func TestMultiresolverOpts(t *testing.T) { 27 t.Parallel() 28 29 wantLog := log.Noop 30 wantCfgs := []multiresolver.ConnectionConfig{ 31 { 32 Address: "testadr1", 33 Endpoint: "testEndpoint1", 34 TLD: "testtld1", 35 }, 36 { 37 Address: "testadr2", 38 Endpoint: "testEndpoint2", 39 TLD: "testtld2", 40 }, 41 } 42 43 mr := multiresolver.NewMultiResolver( 44 multiresolver.WithLogger(wantLog), 45 multiresolver.WithConnectionConfigs(wantCfgs), 46 multiresolver.WithForceDefault(), 47 ) 48 49 if got := multiresolver.GetLogger(mr); got != wantLog { 50 t.Errorf("log: got: %v, want %v", got, wantLog) 51 } 52 if got := multiresolver.GetCfgs(mr); !reflect.DeepEqual(got, wantCfgs) { 53 t.Errorf("cfg: got: %v, want %v", got, wantCfgs) 54 } 55 if !mr.ForceDefault { 56 t.Error("did not set ForceDefault") 57 } 58 } 59 60 func TestPushResolver(t *testing.T) { 61 t.Parallel() 62 63 testCases := []struct { 64 desc string 65 tld string 66 wantErr error 67 }{ 68 { 69 desc: "empty string, default", 70 tld: "", 71 }, 72 { 73 desc: "regular tld, named chain", 74 tld: ".tld", 75 }, 76 } 77 78 for _, tC := range testCases { 79 tC := tC 80 t.Run(tC.desc, func(t *testing.T) { 81 t.Parallel() 82 83 mr := multiresolver.NewMultiResolver() 84 85 if mr.ChainCount(tC.tld) != 0 { 86 t.Fatal("chain should start empty") 87 } 88 89 want := mock.NewResolver() 90 mr.PushResolver(tC.tld, want) 91 92 got := mr.GetChain(tC.tld)[0] 93 if !reflect.DeepEqual(got, want) { 94 t.Error("failed to push") 95 } 96 97 if err := mr.PopResolver(tC.tld); err != nil { 98 t.Error(err) 99 } 100 if mr.ChainCount(tC.tld) > 0 { 101 t.Error("failed to pop") 102 } 103 }) 104 } 105 t.Run("pop empty chain", func(t *testing.T) { 106 t.Parallel() 107 108 mr := multiresolver.NewMultiResolver() 109 err := mr.PopResolver("") 110 if !errors.Is(err, multiresolver.ErrResolverChainEmpty) { 111 t.Errorf("got %v, want %v", err, multiresolver.ErrResolverChainEmpty) 112 } 113 }) 114 } 115 116 func TestResolve(t *testing.T) { 117 t.Parallel() 118 119 addr := newAddr("aaaabbbbccccdddd") 120 addrAlt := newAddr("ddddccccbbbbaaaa") 121 errUnregisteredName := fmt.Errorf("unregistered name") 122 errResolutionFailed := fmt.Errorf("name resolution failed") 123 124 newOKResolver := func(addr Address) resolver.Interface { 125 return mock.NewResolver( 126 mock.WithResolveFunc(func(_ string) (Address, error) { 127 return addr, nil 128 }), 129 ) 130 } 131 newErrResolver := func() resolver.Interface { 132 return mock.NewResolver( 133 mock.WithResolveFunc(func(name string) (Address, error) { 134 return swarm.ZeroAddress, errResolutionFailed 135 }), 136 ) 137 } 138 newUnregisteredNameResolver := func() resolver.Interface { 139 return mock.NewResolver( 140 mock.WithResolveFunc(func(name string) (Address, error) { 141 return swarm.ZeroAddress, errUnregisteredName 142 }), 143 ) 144 } 145 146 testFixture := []struct { 147 tld string 148 res []resolver.Interface 149 expectAdr Address 150 }{ 151 { 152 // Default chain: 153 tld: "", 154 res: []resolver.Interface{ 155 newOKResolver(addr), 156 }, 157 expectAdr: addr, 158 }, 159 { 160 tld: ".tld", 161 res: []resolver.Interface{ 162 newErrResolver(), 163 newErrResolver(), 164 newOKResolver(addr), 165 }, 166 expectAdr: addr, 167 }, 168 { 169 tld: ".good", 170 res: []resolver.Interface{ 171 newOKResolver(addr), 172 newOKResolver(addrAlt), 173 }, 174 expectAdr: addr, 175 }, 176 { 177 tld: ".empty", 178 }, 179 { 180 tld: ".dies", 181 res: []resolver.Interface{ 182 newErrResolver(), 183 newErrResolver(), 184 }, 185 }, 186 { 187 tld: ".unregistered", 188 res: []resolver.Interface{ 189 newUnregisteredNameResolver(), 190 }, 191 }, 192 } 193 194 testCases := []struct { 195 name string 196 wantAdr Address 197 wantErr error 198 }{ 199 { 200 name: "", 201 wantAdr: addr, 202 }, 203 { 204 name: "hello", 205 wantAdr: addr, 206 }, 207 { 208 name: "example.tld", 209 wantAdr: addr, 210 }, 211 { 212 name: ".tld", 213 wantAdr: addr, 214 }, 215 { 216 name: "get.good", 217 wantAdr: addr, 218 }, 219 { 220 // Switch to the default chain: 221 name: "this.empty", 222 wantAdr: addr, 223 }, 224 { 225 name: "this.dies", 226 wantErr: errResolutionFailed, 227 }, 228 { 229 name: "iam.unregistered", 230 wantAdr: swarm.ZeroAddress, 231 wantErr: errUnregisteredName, 232 }, 233 } 234 235 // Load the test fixture. 236 mr := multiresolver.NewMultiResolver() 237 for _, tE := range testFixture { 238 for _, r := range tE.res { 239 mr.PushResolver(tE.tld, r) 240 } 241 } 242 243 for _, tC := range testCases { 244 tC := tC 245 t.Run(tC.name, func(t *testing.T) { 246 t.Parallel() 247 248 addr, err := mr.Resolve(tC.name) 249 if err != nil { 250 if tC.wantErr == nil { 251 t.Fatalf("unexpected error: got %v", err) 252 } 253 if !errors.Is(err, tC.wantErr) { 254 t.Fatalf("got %v, want %v", err, tC.wantErr) 255 } 256 } 257 if !addr.Equal(tC.wantAdr) { 258 t.Errorf("got %q, want %q", addr, tC.wantAdr) 259 } 260 }) 261 } 262 263 t.Run("close all", func(t *testing.T) { 264 if err := mr.Close(); err != nil { 265 t.Fatal(err) 266 } 267 for _, tE := range testFixture { 268 for _, r := range mr.GetChain(tE.tld) { 269 if !r.(*mock.Resolver).IsClosed { 270 t.Errorf("expected %q resolver closed", tE.tld) 271 } 272 } 273 } 274 }) 275 }