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 }