18600: Add update-files test.
authorTom Clegg <tom@curii.com>
Fri, 4 Mar 2022 16:37:45 +0000 (11:37 -0500)
committerTom Clegg <tom@curii.com>
Fri, 4 Mar 2022 16:37:45 +0000 (11:37 -0500)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@curii.com>

lib/controller/localdb/collection_test.go
sdk/go/arvados/fs_backend.go

index efcc830f1e58b8e54c4933e19209357f7ac0b8f1..36108b435182744db99b8564b349205c56f7944a 100644 (file)
@@ -6,16 +6,20 @@ package localdb
 
 import (
        "context"
+       "io/fs"
        "regexp"
+       "sort"
        "strconv"
        "time"
 
        "git.arvados.org/arvados.git/lib/config"
        "git.arvados.org/arvados.git/lib/controller/rpc"
        "git.arvados.org/arvados.git/sdk/go/arvados"
+       "git.arvados.org/arvados.git/sdk/go/arvadosclient"
        "git.arvados.org/arvados.git/sdk/go/arvadostest"
        "git.arvados.org/arvados.git/sdk/go/auth"
        "git.arvados.org/arvados.git/sdk/go/ctxlog"
+       "git.arvados.org/arvados.git/sdk/go/keepclient"
        check "gopkg.in/check.v1"
 )
 
@@ -119,6 +123,100 @@ func (s *CollectionSuite) TestCollectionCreateAndUpdateWithProperties(c *check.C
        }
 }
 
+func (s *CollectionSuite) TestCollectionUpdateFiles(c *check.C) {
+       ctx := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.AdminToken}})
+       foo, err := s.localdb.railsProxy.CollectionCreate(ctx, arvados.CreateOptions{
+               Attrs: map[string]interface{}{
+                       "owner_uuid":    arvadostest.ActiveUserUUID,
+                       "manifest_text": ". acbd18db4cc2f85cedef654fccc4a4d8+3 0:3:foo.txt\n",
+               }})
+       c.Assert(err, check.IsNil)
+       s.localdb.signCollection(ctx, &foo)
+       foobarbaz, err := s.localdb.railsProxy.CollectionCreate(ctx, arvados.CreateOptions{
+               Attrs: map[string]interface{}{
+                       "owner_uuid":    arvadostest.ActiveUserUUID,
+                       "manifest_text": "./foo/bar 73feffa4b7f6bb68e44cf984c85f6e88+3 0:3:baz.txt\n",
+               }})
+       c.Assert(err, check.IsNil)
+       s.localdb.signCollection(ctx, &foobarbaz)
+       wazqux, err := s.localdb.railsProxy.CollectionCreate(ctx, arvados.CreateOptions{
+               Attrs: map[string]interface{}{
+                       "owner_uuid":    arvadostest.ActiveUserUUID,
+                       "manifest_text": "./waz d85b1213473c2fd7c2045020a6b9c62b+3 0:3:qux.txt\n",
+               }})
+       c.Assert(err, check.IsNil)
+       s.localdb.signCollection(ctx, &wazqux)
+
+       ctx = auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.ActiveTokenV2}})
+
+       // Create using content from existing collections
+       dst, err := s.localdb.CollectionCreate(ctx, arvados.CreateOptions{
+               Attrs: map[string]interface{}{
+                       "owner_uuid": arvadostest.ActiveUserUUID,
+                       "splices": map[string]string{
+                               "/f": foo.PortableDataHash + "/foo.txt",
+                               "/b": foobarbaz.PortableDataHash + "/foo/bar",
+                               "/q": wazqux.PortableDataHash + "/",
+                               "/w": wazqux.PortableDataHash + "/waz",
+                       },
+               }})
+       c.Assert(err, check.IsNil)
+       s.expectFiles(c, dst, "f", "b/baz.txt", "q/waz/qux.txt", "w/qux.txt")
+
+       // Delete a file and a directory
+       dst, err = s.localdb.CollectionUpdate(ctx, arvados.UpdateOptions{
+               UUID: dst.UUID,
+               Attrs: map[string]interface{}{
+                       "splices": map[string]string{
+                               "/f":     "",
+                               "/q/waz": "",
+                       },
+               }})
+       c.Assert(err, check.IsNil)
+       s.expectFiles(c, dst, "b/baz.txt", "q/", "w/qux.txt")
+
+       // Move content within collection
+       dst, err = s.localdb.CollectionUpdate(ctx, arvados.UpdateOptions{
+               UUID: dst.UUID,
+               Attrs: map[string]interface{}{
+                       "splices": map[string]string{
+                               "/b":              "",
+                               "/quux/corge.txt": dst.PortableDataHash + "/b/baz.txt",
+                       },
+               }})
+       c.Assert(err, check.IsNil)
+       s.expectFiles(c, dst, "q/", "w/qux.txt", "quux/corge.txt")
+}
+
+// Wrap arvados.FileSystem to satisfy the fs.FS interface (until the
+// SDK offers a neater solution) so we can use fs.WalkDir().
+type filesystemfs struct {
+       arvados.FileSystem
+}
+
+func (fs filesystemfs) Open(path string) (fs.File, error) {
+       f, err := fs.FileSystem.Open(path)
+       return f, err
+}
+
+func (s *CollectionSuite) expectFiles(c *check.C, coll arvados.Collection, expected ...string) {
+       client := arvados.NewClientFromEnv()
+       ac, err := arvadosclient.New(client)
+       c.Assert(err, check.IsNil)
+       kc, err := keepclient.MakeKeepClient(ac)
+       c.Assert(err, check.IsNil)
+       cfs, err := coll.FileSystem(arvados.NewClientFromEnv(), kc)
+       c.Assert(err, check.IsNil)
+       var found []string
+       fs.WalkDir(filesystemfs{cfs}, "/", func(path string, d fs.DirEntry, err error) error {
+               found = append(found, path)
+               return nil
+       })
+       sort.Strings(found)
+       sort.Strings(expected)
+       c.Check(found, check.DeepEquals, expected)
+}
+
 func (s *CollectionSuite) TestSignatures(c *check.C) {
        ctx := auth.NewContext(context.Background(), &auth.Credentials{Tokens: []string{arvadostest.ActiveTokenV2}})
 
index 32365a5317ec79d50dd7f47f71359bcd6536f881..445ac8103008f0104f1f53d731843bc893ea3d33 100644 (file)
@@ -6,6 +6,7 @@ package arvados
 
 import (
        "context"
+       "errors"
        "io"
 )
 
@@ -30,3 +31,16 @@ type keepClient interface {
 type apiClient interface {
        RequestAndDecode(dst interface{}, method, path string, body io.Reader, params interface{}) error
 }
+
+var errStubClient = errors.New("stub client")
+
+type StubClient struct{}
+
+func (*StubClient) ReadAt(string, []byte, int) (int, error) { return 0, errStubClient }
+func (*StubClient) LocalLocator(string) (string, error)     { return "", errStubClient }
+func (*StubClient) BlockWrite(context.Context, BlockWriteOptions) (BlockWriteResponse, error) {
+       return BlockWriteResponse{}, errStubClient
+}
+func (*StubClient) RequestAndDecode(_ interface{}, _, _ string, _ io.Reader, _ interface{}) error {
+       return errStubClient
+}