github.com/ethersphere/bee/v2@v2.2.0/pkg/manifest/mantaray/node_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 mantaray_test
     6  
     7  import (
     8  	"bytes"
     9  	"context"
    10  	"errors"
    11  	"strconv"
    12  	"testing"
    13  
    14  	"github.com/ethersphere/bee/v2/pkg/manifest/mantaray"
    15  )
    16  
    17  func TestNilPath(t *testing.T) {
    18  	t.Parallel()
    19  
    20  	ctx := context.Background()
    21  	n := mantaray.New()
    22  	_, err := n.Lookup(ctx, nil, nil)
    23  	if err != nil {
    24  		t.Fatalf("expected no error, got %v", err)
    25  	}
    26  }
    27  
    28  func TestAddAndLookup(t *testing.T) {
    29  	t.Parallel()
    30  
    31  	ctx := context.Background()
    32  	n := mantaray.New()
    33  	testCases := [][]byte{
    34  		[]byte("aaaaaa"),
    35  		[]byte("aaaaab"),
    36  		[]byte("abbbb"),
    37  		[]byte("abbba"),
    38  		[]byte("bbbbba"),
    39  		[]byte("bbbaaa"),
    40  		[]byte("bbbaab"),
    41  		[]byte("aa"),
    42  		[]byte("b"),
    43  	}
    44  	for i := 0; i < len(testCases); i++ {
    45  		c := testCases[i]
    46  		e := append(make([]byte, 32-len(c)), c...)
    47  		err := n.Add(ctx, c, e, nil, nil)
    48  		if err != nil {
    49  			t.Fatalf("expected no error, got %v", err)
    50  		}
    51  		for j := 0; j < i; j++ {
    52  			d := testCases[j]
    53  			m, err := n.Lookup(ctx, d, nil)
    54  			if err != nil {
    55  				t.Fatalf("expected no error, got %v", err)
    56  			}
    57  			de := append(make([]byte, 32-len(d)), d...)
    58  			if !bytes.Equal(m, de) {
    59  				t.Fatalf("expected value %x, got %x", d, m)
    60  			}
    61  		}
    62  	}
    63  }
    64  
    65  func TestAddAndLookupNode(t *testing.T) {
    66  	t.Parallel()
    67  
    68  	for _, tc := range []struct {
    69  		name  string
    70  		toAdd [][]byte
    71  	}{
    72  		{
    73  			name: "a",
    74  			toAdd: [][]byte{
    75  				[]byte("aaaaaa"),
    76  				[]byte("aaaaab"),
    77  				[]byte("abbbb"),
    78  				[]byte("abbba"),
    79  				[]byte("bbbbba"),
    80  				[]byte("bbbaaa"),
    81  				[]byte("bbbaab"),
    82  				[]byte("aa"),
    83  				[]byte("b"),
    84  			},
    85  		},
    86  		{
    87  			name: "simple",
    88  			toAdd: [][]byte{
    89  				[]byte("/"),
    90  				[]byte("index.html"),
    91  				[]byte("img/1.png"),
    92  				[]byte("img/2.png"),
    93  				[]byte("robots.txt"),
    94  			},
    95  		},
    96  		{
    97  			// mantaray.nodePrefixMaxSize number of '.'
    98  			name: "nested-value-node-is-recognized",
    99  			toAdd: [][]byte{
   100  				[]byte("..............................@"),
   101  				[]byte(".............................."),
   102  			},
   103  		},
   104  		{
   105  			name: "nested-prefix-is-not-collapsed",
   106  			toAdd: [][]byte{
   107  				[]byte("index.html"),
   108  				[]byte("img/1.png"),
   109  				[]byte("img/2/test1.png"),
   110  				[]byte("img/2/test2.png"),
   111  				[]byte("robots.txt"),
   112  			},
   113  		},
   114  		{
   115  			name: "conflicting-path",
   116  			toAdd: [][]byte{
   117  				[]byte("app.js.map"),
   118  				[]byte("app.js"),
   119  			},
   120  		},
   121  		{
   122  			name: "spa-website",
   123  			toAdd: [][]byte{
   124  				[]byte("css/"),
   125  				[]byte("css/app.css"),
   126  				[]byte("favicon.ico"),
   127  				[]byte("img/"),
   128  				[]byte("img/logo.png"),
   129  				[]byte("index.html"),
   130  				[]byte("js/"),
   131  				[]byte("js/chunk-vendors.js.map"),
   132  				[]byte("js/chunk-vendors.js"),
   133  				[]byte("js/app.js.map"),
   134  				[]byte("js/app.js"),
   135  			},
   136  		},
   137  	} {
   138  		ctx := context.Background()
   139  		tc := tc
   140  		t.Run(tc.name, func(t *testing.T) {
   141  			t.Parallel()
   142  
   143  			n := mantaray.New()
   144  
   145  			for i := 0; i < len(tc.toAdd); i++ {
   146  				c := tc.toAdd[i]
   147  				e := append(make([]byte, 32-len(c)), c...)
   148  				err := n.Add(ctx, c, e, nil, nil)
   149  				if err != nil {
   150  					t.Fatalf("expected no error, got %v", err)
   151  				}
   152  				for j := 0; j < i+1; j++ {
   153  					d := tc.toAdd[j]
   154  					node, err := n.LookupNode(ctx, d, nil)
   155  					if err != nil {
   156  						t.Fatalf("expected no error, got %v", err)
   157  					}
   158  					if !node.IsValueType() {
   159  						t.Fatalf("expected value type, got %v", strconv.FormatInt(int64(node.NodeType()), 2))
   160  					}
   161  					de := append(make([]byte, 32-len(d)), d...)
   162  					if !bytes.Equal(node.Entry(), de) {
   163  						t.Fatalf("expected value %x, got %x", d, node.Entry())
   164  					}
   165  				}
   166  			}
   167  		})
   168  
   169  		t.Run(tc.name+"/with load save", func(t *testing.T) {
   170  			t.Parallel()
   171  
   172  			n := mantaray.New()
   173  
   174  			for i := 0; i < len(tc.toAdd); i++ {
   175  				c := tc.toAdd[i]
   176  				e := append(make([]byte, 32-len(c)), c...)
   177  				err := n.Add(ctx, c, e, nil, nil)
   178  				if err != nil {
   179  					t.Fatalf("expected no error, got %v", err)
   180  				}
   181  			}
   182  			ls := newMockLoadSaver()
   183  			err := n.Save(ctx, ls)
   184  			if err != nil {
   185  				t.Fatal(err)
   186  			}
   187  
   188  			n2 := mantaray.NewNodeRef(n.Reference())
   189  
   190  			for j := 0; j < len(tc.toAdd); j++ {
   191  				d := tc.toAdd[j]
   192  				node, err := n2.LookupNode(ctx, d, ls)
   193  				if err != nil {
   194  					t.Fatalf("expected no error, got %v", err)
   195  				}
   196  				if !node.IsValueType() {
   197  					t.Fatalf("expected value type, got %v", strconv.FormatInt(int64(node.NodeType()), 2))
   198  				}
   199  				de := append(make([]byte, 32-len(d)), d...)
   200  				if !bytes.Equal(node.Entry(), de) {
   201  					t.Fatalf("expected value %x, got %x", d, node.Entry())
   202  				}
   203  			}
   204  		})
   205  	}
   206  }
   207  
   208  func TestRemove(t *testing.T) {
   209  	t.Parallel()
   210  
   211  	for _, tc := range []struct {
   212  		name     string
   213  		toAdd    []mantaray.NodeEntry
   214  		toRemove [][]byte
   215  	}{
   216  		{
   217  			name: "simple",
   218  			toAdd: []mantaray.NodeEntry{
   219  				{
   220  					Path: []byte("/"),
   221  					Metadata: map[string]string{
   222  						"index-document": "index.html",
   223  					},
   224  				},
   225  				{
   226  					Path: []byte("index.html"),
   227  				},
   228  				{
   229  					Path: []byte("img/1.png"),
   230  				},
   231  				{
   232  					Path: []byte("img/2.png"),
   233  				},
   234  				{
   235  					Path: []byte("robots.txt"),
   236  				},
   237  			},
   238  			toRemove: [][]byte{
   239  				[]byte("img/2.png"),
   240  			},
   241  		},
   242  		{
   243  			name: "nested-prefix-is-not-collapsed",
   244  			toAdd: []mantaray.NodeEntry{
   245  				{
   246  					Path: []byte("index.html"),
   247  				},
   248  				{
   249  					Path: []byte("img/1.png"),
   250  				},
   251  				{
   252  					Path: []byte("img/2/test1.png"),
   253  				},
   254  				{
   255  					Path: []byte("img/2/test2.png"),
   256  				},
   257  				{
   258  					Path: []byte("robots.txt"),
   259  				},
   260  			},
   261  			toRemove: [][]byte{
   262  				[]byte("img/2/test1.png"),
   263  			},
   264  		},
   265  	} {
   266  		ctx := context.Background()
   267  		tc := tc
   268  		t.Run(tc.name, func(t *testing.T) {
   269  			t.Parallel()
   270  
   271  			n := mantaray.New()
   272  
   273  			for i := 0; i < len(tc.toAdd); i++ {
   274  				c := tc.toAdd[i].Path
   275  				e := tc.toAdd[i].Entry
   276  				if len(e) == 0 {
   277  					e = append(make([]byte, 32-len(c)), c...)
   278  				}
   279  				m := tc.toAdd[i].Metadata
   280  				err := n.Add(ctx, c, e, m, nil)
   281  				if err != nil {
   282  					t.Fatalf("expected no error, got %v", err)
   283  				}
   284  				for j := 0; j < i; j++ {
   285  					d := tc.toAdd[j].Path
   286  					m, err := n.Lookup(ctx, d, nil)
   287  					if err != nil {
   288  						t.Fatalf("expected no error, got %v", err)
   289  					}
   290  					de := append(make([]byte, 32-len(d)), d...)
   291  					if !bytes.Equal(m, de) {
   292  						t.Fatalf("expected value %x, got %x", d, m)
   293  					}
   294  				}
   295  			}
   296  
   297  			for i := 0; i < len(tc.toRemove); i++ {
   298  				c := tc.toRemove[i]
   299  				err := n.Remove(ctx, c, nil)
   300  				if err != nil {
   301  					t.Fatalf("expected no error, got %v", err)
   302  				}
   303  				_, err = n.Lookup(ctx, c, nil)
   304  				if !errors.Is(err, mantaray.ErrNotFound) {
   305  					t.Fatalf("expected not found error, got %v", err)
   306  				}
   307  			}
   308  
   309  		})
   310  	}
   311  }
   312  
   313  func TestHasPrefix(t *testing.T) {
   314  	t.Parallel()
   315  
   316  	for _, tc := range []struct {
   317  		name        string
   318  		toAdd       [][]byte
   319  		testPrefix  [][]byte
   320  		shouldExist []bool
   321  	}{
   322  		{
   323  			name: "simple",
   324  			toAdd: [][]byte{
   325  				[]byte("index.html"),
   326  				[]byte("img/1.png"),
   327  				[]byte("img/2.png"),
   328  				[]byte("robots.txt"),
   329  			},
   330  			testPrefix: [][]byte{
   331  				[]byte("img/"),
   332  				[]byte("images/"),
   333  			},
   334  			shouldExist: []bool{
   335  				true,
   336  				false,
   337  			},
   338  		},
   339  		{
   340  			name: "nested-single",
   341  			toAdd: [][]byte{
   342  				[]byte("some-path/file.ext"),
   343  			},
   344  			testPrefix: [][]byte{
   345  				[]byte("some-path/"),
   346  				[]byte("some-path/file"),
   347  				[]byte("some-other-path/"),
   348  			},
   349  			shouldExist: []bool{
   350  				true,
   351  				true,
   352  				false,
   353  			},
   354  		},
   355  	} {
   356  		ctx := context.Background()
   357  		tc := tc
   358  		t.Run(tc.name, func(t *testing.T) {
   359  			t.Parallel()
   360  
   361  			n := mantaray.New()
   362  
   363  			for i := 0; i < len(tc.toAdd); i++ {
   364  				c := tc.toAdd[i]
   365  				e := append(make([]byte, 32-len(c)), c...)
   366  				err := n.Add(ctx, c, e, nil, nil)
   367  				if err != nil {
   368  					t.Fatalf("expected no error, got %v", err)
   369  				}
   370  			}
   371  
   372  			for i := 0; i < len(tc.testPrefix); i++ {
   373  				testPrefix := tc.testPrefix[i]
   374  				shouldExist := tc.shouldExist[i]
   375  
   376  				exists, err := n.HasPrefix(ctx, testPrefix, nil)
   377  				if err != nil {
   378  					t.Fatalf("expected no error, got %v", err)
   379  				}
   380  
   381  				if shouldExist != exists {
   382  					t.Errorf("expected prefix path %s to be %t, was %t", testPrefix, shouldExist, exists)
   383  				}
   384  			}
   385  
   386  		})
   387  	}
   388  }