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  }