package weed_server import ( "context" "testing" "github.com/seaweedfs/seaweedfs/weed/pb/filer_pb" "github.com/seaweedfs/seaweedfs/weed/util" "github.com/stretchr/testify/assert" "github.com/viant/ptrie" "google.golang.org/grpc" ) func TestPtrie(t *testing.T) { b := []byte("/topics/abc/dev") excludedTrie := ptrie.New[bool]() excludedTrie.Put([]byte("/topics/abc/d"), true) excludedTrie.Put([]byte("/topics/abc"), true) assert.True(t, excludedTrie.MatchPrefix(b, func(key []byte, value bool) bool { println("matched1", string(key)) return true })) assert.True(t, excludedTrie.MatchAll(b, func(key []byte, value bool) bool { println("matched2", string(key)) return true })) assert.False(t, excludedTrie.MatchAll([]byte("/topics/ab"), func(key []byte, value bool) bool { println("matched3", string(key)) return true })) assert.False(t, excludedTrie.Has(b)) } type captureTraverseStream struct { grpc.ServerStream ctx context.Context visited []string } func (s *captureTraverseStream) Context() context.Context { return s.ctx } func (s *captureTraverseStream) Send(resp *filer_pb.TraverseBfsMetadataResponse) error { dir := resp.Directory if dir != "/" { dir += "/" } s.visited = append(s.visited, dir+resp.Entry.Name) return nil } func TestTraverseBfsMetadata(t *testing.T) { store := newRenameTestStore() // "/.system-data" shares the "/.system" byte prefix but is a different // path component, so it must not be excluded. for _, dir := range []string{"/", "/a", "/a/sub", "/b", "/.system", "/.system-data"} { store.entries[dir] = newDirectoryEntry(dir, 1) } for _, file := range []string{"/a/f1", "/a/sub/f2", "/b/f3", "/.system/secret", "/.system-data/keep"} { store.entries[file] = newFileEntry(file, 2) } server := &FilerServer{filer: newRenameTestFiler(t, store)} stream := &captureTraverseStream{ctx: context.Background()} err := server.TraverseBfsMetadata(&filer_pb.TraverseBfsMetadataRequest{ Directory: "/", ExcludedPrefixes: []string{"/.system"}, }, stream) assert.NoError(t, err) // The excluded subtree is skipped; everything else (including the // /.system-data sibling) is visited exactly once. assert.ElementsMatch(t, []string{ "/", "/a", "/a/f1", "/a/sub", "/a/sub/f2", "/b", "/b/f3", "/.system-data", "/.system-data/keep", }, stream.visited) // Each entry's parent must be streamed before the entry itself, so a // consumer can apply the tree top-down. seen := make(map[string]bool) for _, path := range stream.visited { if path != "/" { parent, _ := util.FullPath(path).DirAndName() assert.Truef(t, seen[parent], "parent %s of %s not streamed first", parent, path) } seen[path] = true } } var _ filer_pb.SeaweedFiler_TraverseBfsMetadataServer = (*captureTraverseStream)(nil)