[ARVADOS] updated: 1.1.2-314-g9451dec

Git user git at public.curoverse.com
Thu Feb 8 22:41:15 EST 2018


Summary of changes:
 .gitignore                                         |   1 +
 .../app/assets/javascripts/application.js          |   1 +
 .../app/assets/javascripts/components/search.js    |  12 +-
 .../app/assets/javascripts/components/sessions.js  |  16 +-
 .../app/assets/javascripts/models/session_db.js    | 151 ++++-
 .../controllers/container_requests_controller.rb   |  11 +
 apps/workbench/app/models/container_work_unit.rb   |  36 +-
 .../container_requests/_show_recent_rows.html.erb  |   2 +-
 .../app/views/projects/_show_dashboard.html.erb    |  15 +-
 apps/workbench/app/views/search/index.html         |   7 +
 apps/workbench/app/views/sessions/index.html       |   7 +
 apps/workbench/config/application.default.yml      |   2 +-
 apps/workbench/npm_packages                        |   1 +
 .../container_requests_controller_test.rb          |  16 +-
 apps/workbench/test/unit/work_unit_test.rb         |   2 +-
 build/libcloud-pin.sh                              |   2 +-
 build/run-tests.sh                                 |  34 +-
 doc/_includes/_mount_types.liquid                  |   2 +-
 sdk/R/.Rbuildignore                                |   2 +
 sdk/R/ArvadosR.Rproj                               |  20 +
 sdk/R/DESCRIPTION                                  |  20 +
 sdk/R/NAMESPACE                                    |  10 +
 sdk/R/R/Arvados.R                                  | 183 ++++++
 sdk/R/R/ArvadosFile.R                              | 220 +++++++
 sdk/R/R/Collection.R                               | 184 ++++++
 sdk/R/R/CollectionTree.R                           | 124 ++++
 sdk/R/R/HttpParser.R                               |  55 ++
 sdk/R/R/HttpRequest.R                              |  98 ++++
 sdk/R/R/RESTService.R                              | 349 ++++++++++++
 sdk/R/R/Subcollection.R                            | 288 ++++++++++
 sdk/R/R/util.R                                     |  54 ++
 sdk/R/README                                       | 251 ++++++++
 sdk/R/man/Arvados.Rd                               |  25 +
 sdk/R/man/ArvadosFile.Rd                           |  14 +
 sdk/R/man/Collection.Rd                            |  17 +
 sdk/R/man/CollectionTree.Rd                        |  17 +
 sdk/R/man/HttpParser.Rd                            |  14 +
 sdk/R/man/Subcollection.Rd                         |  14 +
 sdk/R/run_test.R                                   |   7 +
 sdk/R/tests/testthat.R                             |   4 +
 sdk/R/tests/testthat/fakes/FakeArvados.R           |  35 ++
 sdk/R/tests/testthat/fakes/FakeHttpParser.R        |  56 ++
 sdk/R/tests/testthat/fakes/FakeHttpRequest.R       | 166 ++++++
 sdk/R/tests/testthat/fakes/FakeRESTService.R       | 167 ++++++
 sdk/R/tests/testthat/test-Arvados.R                | 306 ++++++++++
 sdk/R/tests/testthat/test-ArvadosFile.R            | 271 +++++++++
 sdk/R/tests/testthat/test-Collection.R             | 260 +++++++++
 sdk/R/tests/testthat/test-CollectionTree.R         | 102 ++++
 sdk/R/tests/testthat/test-HttpParser.R             |  92 +++
 sdk/R/tests/testthat/test-HttpRequest.R            |  28 +
 sdk/R/tests/testthat/test-RESTService.R            | 633 +++++++++++++++++++++
 sdk/R/tests/testthat/test-Subcollection.R          | 356 ++++++++++++
 sdk/R/tests/testthat/test-util.R                   |  85 +++
 sdk/cwl/arvados_cwl/__init__.py                    |  15 +-
 sdk/cwl/arvados_cwl/arvcontainer.py                |  23 +-
 sdk/cwl/arvados_cwl/arvtool.py                     |   9 +-
 sdk/cwl/arvados_cwl/pathmapper.py                  |  14 +-
 sdk/cwl/arvados_cwl/runner.py                      |   2 +-
 sdk/cwl/setup.py                                   |   2 +-
 sdk/cwl/tests/test_make_output.py                  |   2 +
 sdk/go/arvados/fs_base.go                          | 176 +++---
 sdk/go/arvados/fs_collection.go                    |  33 +-
 sdk/go/arvados/fs_collection_test.go               |   4 +-
 sdk/go/arvados/fs_deferred.go                      |  26 +-
 sdk/go/arvados/fs_filehandle.go                    |   8 +-
 sdk/go/arvados/fs_getternode.go                    |   4 +-
 sdk/go/arvados/fs_project.go                       |  41 +-
 sdk/go/arvados/fs_project_test.go                  |  78 +++
 sdk/go/arvados/fs_site.go                          |  35 +-
 services/api/app/models/container.rb               |  24 +-
 services/api/app/models/container_request.rb       |  13 +-
 services/api/test/fixtures/container_requests.yml  |   4 +-
 services/api/test/unit/container_test.rb           |   4 +-
 services/crunch-run/crunchrun.go                   | 129 ++++-
 services/crunch-run/crunchrun_test.go              |  84 +--
 services/nodemanager/setup.py                      |   4 +-
 tools/arvbox/lib/arvbox/docker/Dockerfile.base     |   2 +-
 77 files changed, 5301 insertions(+), 280 deletions(-)
 create mode 100644 sdk/R/.Rbuildignore
 create mode 100644 sdk/R/ArvadosR.Rproj
 create mode 100644 sdk/R/DESCRIPTION
 create mode 100644 sdk/R/NAMESPACE
 create mode 100644 sdk/R/R/Arvados.R
 create mode 100644 sdk/R/R/ArvadosFile.R
 create mode 100644 sdk/R/R/Collection.R
 create mode 100644 sdk/R/R/CollectionTree.R
 create mode 100644 sdk/R/R/HttpParser.R
 create mode 100644 sdk/R/R/HttpRequest.R
 create mode 100644 sdk/R/R/RESTService.R
 create mode 100644 sdk/R/R/Subcollection.R
 create mode 100644 sdk/R/R/util.R
 create mode 100644 sdk/R/README
 create mode 100644 sdk/R/man/Arvados.Rd
 create mode 100644 sdk/R/man/ArvadosFile.Rd
 create mode 100644 sdk/R/man/Collection.Rd
 create mode 100644 sdk/R/man/CollectionTree.Rd
 create mode 100644 sdk/R/man/HttpParser.Rd
 create mode 100644 sdk/R/man/Subcollection.Rd
 create mode 100644 sdk/R/run_test.R
 create mode 100644 sdk/R/tests/testthat.R
 create mode 100644 sdk/R/tests/testthat/fakes/FakeArvados.R
 create mode 100644 sdk/R/tests/testthat/fakes/FakeHttpParser.R
 create mode 100644 sdk/R/tests/testthat/fakes/FakeHttpRequest.R
 create mode 100644 sdk/R/tests/testthat/fakes/FakeRESTService.R
 create mode 100644 sdk/R/tests/testthat/test-Arvados.R
 create mode 100644 sdk/R/tests/testthat/test-ArvadosFile.R
 create mode 100644 sdk/R/tests/testthat/test-Collection.R
 create mode 100644 sdk/R/tests/testthat/test-CollectionTree.R
 create mode 100644 sdk/R/tests/testthat/test-HttpParser.R
 create mode 100644 sdk/R/tests/testthat/test-HttpRequest.R
 create mode 100644 sdk/R/tests/testthat/test-RESTService.R
 create mode 100644 sdk/R/tests/testthat/test-Subcollection.R
 create mode 100644 sdk/R/tests/testthat/test-util.R
 create mode 100644 sdk/go/arvados/fs_project_test.go

       via  9451dec1ace2370015b4c75367076cb5d4901f7e (commit)
       via  d1ac0920b9f8c4b793cf33a7016c1dfad4ffba10 (commit)
       via  50b3e54b41ada32f84b154b35f7b02b6c0217c8e (commit)
       via  acb392d097b6dc72ce0953d22d245b039b62fccc (commit)
       via  8fb1de64d0caddc9fc533a964470de799b6044ff (commit)
       via  067ca04652413e2bacd76e9ac5c5c245aa27a291 (commit)
       via  10c8c1871bef6d88ae27797e4b389fbf8649f4b0 (commit)
       via  1b350dc780c38740819ff0dbb495557742aabd1a (commit)
       via  fa9f5461910fede92df37bfce1e46514a59861eb (commit)
       via  abdc3d88ac10b8f3b634b4f1edd46e3597d54ee2 (commit)
       via  0312a5e5aa076fa3458dd83a33e72663d23bb1ba (commit)
       via  d20683e4d068d673c481191b56e770f61c3cb208 (commit)
       via  6331a6c3edee1fef0dc22eb2e2407f2c60168816 (commit)
       via  318d42f0d64cfca262eae5e902ea6fecb724c89a (commit)
       via  0e3c1f9c71f537d000459cbd3159ca6c198461c8 (commit)
       via  8ca0b1449607ded51e908481cc4660c20f43a777 (commit)
       via  bf97bb37d38df9d6edd1a6b0c4227ee9846a4905 (commit)
       via  b3e8a483835334becbef9cba2bebbcf08df47c15 (commit)
       via  75fd99e49f880aac55ae568c76c5151857e6beff (commit)
       via  5f6738f134e1abb359fc8e8c61751263db88d4b6 (commit)
       via  aa798e6915bd39296bca8f62fd3476293c25f436 (commit)
       via  23baab324564d36322b265c7fd904a0b4548c195 (commit)
       via  0faa78426b42eb7cb40822c0963b15f07c1aa9cf (commit)
       via  bb141976709b75a8b8cdf3135fc1d73e22e7ba72 (commit)
       via  03c82ef2950a25085e8d8ec0dc5d261fa1ca7963 (commit)
       via  2eb85f70168d331e49e9d38bfbd2292d586dfcc1 (commit)
       via  dac01e1015f4d769a929651a74096e8a13592cf7 (commit)
       via  5857ebe3b0e512d76871020f1b08d49a9f4de70b (commit)
       via  06237272c9c8b3bfefe00308b2749c8df823ebdf (commit)
       via  c5795cc6f73d5affc55a332fcddc37fa56636f9a (commit)
       via  9359659d79a0c17265ff8a09e896920243a1b800 (commit)
       via  fd228a5ac00d71170eadef15560ced417b1d3909 (commit)
       via  d03facf18d724c52c09604710b074d465febfece (commit)
       via  086f6cc8645e655f75c84268e7e758856a07be87 (commit)
       via  bcb86b69fba693af210e82d40d92854e609157c4 (commit)
       via  23995e4bd823ff1a9f4986ac2b852fd35d740940 (commit)
       via  f64238be677ff7f67cb5ac71ecac534d0c4aa488 (commit)
       via  294e83e3d69e3da8dbced2059323d8680349f548 (commit)
       via  5c6b040cabe60623364f19dc35920a084d6c6fc6 (commit)
       via  69b7576df3796887ebe754a71437f6dc3032f119 (commit)
       via  62e5b36b38e9da03ea0c84256d433b4d21194da3 (commit)
       via  d3dd0147fc7c0e344b4cca1fb92d7c500924bd37 (commit)
       via  e1d26636c385f4c09484673b1b90eec6191ba6c5 (commit)
       via  14e0d031833b75c2bbbfe796294934aea2da3d19 (commit)
       via  29e4cf39674f54e5607d84d612ff867a4add0347 (commit)
       via  ef2889f20ad25c30abb05c53cc5e08e2c2ed97d3 (commit)
       via  6459c61b9cca7d2382d01c20d1f749a7dc8d21e0 (commit)
       via  c98c533d5c971efd1d3b122076c5abe0736f8423 (commit)
       via  c8891a5eeec540404c7aff02a200fd95f6dbe64b (commit)
       via  3e51fd869e600fd3d60e892346896fd9ce3d8c9c (commit)
       via  4da7a9b5c11caf085c14cbf0eacdc16b6f6d7fa5 (commit)
       via  4e78fdb8c41ee73a0f14a349fe4edcfdb1523458 (commit)
       via  bf59702692c89a809f102d8bd4b9caf531f4c9be (commit)
       via  76a7dd09a977c109de100884500b531e6bbe2166 (commit)
       via  11eda09c7340da2c0a01259e3711758782c9b1c9 (commit)
       via  bd1378553152e98ffd0e9ecf68dc0f92ea3ff186 (commit)
       via  25da01646d0fc0d5b49cdeaa10173beabfd2e8b9 (commit)
       via  1178add6cefa51f73dd9a229899ea906d297be5a (commit)
       via  44ab8ee44302102a7cd5289ef7336d7a94594558 (commit)
       via  7471c3fb9752482dccae508c34874f9b3c77dfb1 (commit)
       via  0b869f3fab26c33515cd9b2f44e0ed9c8c542698 (commit)
       via  0488e81c85948faa6a14ca437d9e594d91bcbbd8 (commit)
       via  14b4a1acc30cf4c84135ec7580d228ad1aacca17 (commit)
       via  59eb2058e7111581645c960ba868f49f0fed152b (commit)
       via  78de557466248e1a193e07ae1945b29a23fc56a8 (commit)
       via  3a6a89199e2478454905731ccef0868d5fdd6f8f (commit)
       via  5358498e3f2c0dd73231dca8ca82f9ad164854f7 (commit)
       via  3f5268c5a8d6a72597a05bba5dd6e0e5e67457a9 (commit)
       via  6f1b9ffa9cf4abe9f08455346c917f66b8c5e9a5 (commit)
       via  64aee8cfd4164f3c0dae26fe62cc9ee22b16782b (commit)
       via  c2a07597440e4db06481d2532adc317331df441b (commit)
       via  95c228e25cd1a483ec391a9b2c5d6fb048f620f1 (commit)
       via  4dda3a5b85afbac450d958d81e2acb013c5bae20 (commit)
       via  1499d395e3d2ef62334e349f7bc4ae2cfd0418aa (commit)
       via  2d451314078739464fbb754791bf6f1d4a8fad1c (commit)
       via  f1bde50ee2e8b8fa8533518006f09546a62f7a87 (commit)
       via  af17604c5a93830380fb50db93ce543926c116cf (commit)
       via  539f2b151c57a76c9a8c0d49ef7ee5c0bac39de7 (commit)
       via  d25be127db660e0c3c97bf53f8488d73e28b86d3 (commit)
       via  38ceac30a22ac3c506ca69263ff9e2640e5bd71e (commit)
       via  29df5af6f77c1f24593ecda397a56f0632876ce2 (commit)
       via  defe89ef5c3e8995b275120f060cf85296f6396b (commit)
       via  b5c2d27b55ff8490818548bc077975fbf37b3a1f (commit)
       via  68d1c59bc33df1b002754b958b6887896f2a40d5 (commit)
       via  b0f36fd28ee29321d368852bd14b61485e758af3 (commit)
       via  7f2de2ec1d52c8e5984b610c5930f2d9629bd357 (commit)
       via  67b46a6c360a18fee84846d75622539220eca211 (commit)
       via  937c64f38ff59f11616ea8932b24116530f2e60f (commit)
       via  ecb7d4501373a21ae69494beee8252f107ec1b56 (commit)
       via  1ece35a0faae97687c2dd370f6b8a61aaac505c2 (commit)
       via  2d3726dd11046146731f7f7391659a5eaf44702b (commit)
       via  7b76c49887aecdb2bf0be7eecf8f5b271d5f0c38 (commit)
       via  8daddfe53514b71ef229e9c2985e116fa6614858 (commit)
       via  d246f53c1d991f1572d6701569aa8c7eac4d722d (commit)
       via  b37da0c1488f68491f40bbe5bfbe2e00a12137e9 (commit)
       via  3b4520cc6aa20a3db3b469c32c2b29ccee8933c5 (commit)
       via  ec836ed648758619ed35153e52016079adce99b7 (commit)
       via  91801cb4c303db0fbf701aa34e646e0dc4187f05 (commit)
       via  76c2e8d11e3c644f1603adbef3222afaacd6a279 (commit)
       via  d645f41a7f082e92288cb07cfa4527ff3edb408a (commit)
       via  f4da35a4dc44a18c8371c9e42a03fa5dc96c53d3 (commit)
       via  99bec637f6d4384a8d6f3c2cb27eb32d13c14f21 (commit)
       via  3d51cb80240a582a901855d7a7e79b70dcf28bab (commit)
       via  c65dfd0d76b9432b1ca305d2bf39d8bb309124a2 (commit)
       via  082df78ff6abc6ecb5fb817649111e7e6ef967a2 (commit)
       via  7c8c1719232d0a5b96e6cbfa46c94faeee65cf05 (commit)
       via  693b1f491499c33d82c3950aaa8f0b754a50c219 (commit)
       via  e72f801012e68e7a223a64d4e90bfa2cc66a9254 (commit)
       via  074f020c32c55c017433ac5a294a5e0b73b360ad (commit)
       via  2fcdd3f845647243517af895d49c812f9c2eaae2 (commit)
       via  62a2ccba46cb5b83e510e727afa44eee2e893676 (commit)
       via  d5cb3c081c0e9a8d7698feb7c04ade6f385a5471 (commit)
       via  790a912ff48b90cba284a0a6b5b4e34db7b22078 (commit)
       via  9d633e1cc0f3842edf6cef1a9f6d7f4724ab81bf (commit)
       via  11b903121f9c9505e529bb4b8965d56c1f8f96e0 (commit)
       via  f15c8a8ef1af9d823030f4c6383ba2560a78a4fa (commit)
       via  df8b4a86d08b4da0f5959766257664c9af89343b (commit)
       via  7da8eaf51a23ab23369b6e65f0634448cc4aeb3b (commit)
       via  05d6f9301e863a2b0aad1178d629354601f14325 (commit)
       via  5c5ec11a744d47f7235e5a1862d2d22288ffe90f (commit)
       via  8b29c17f3dcbfa2601b6be4921316340967af17b (commit)
       via  f67c59f3fea793ed3ccea7f5a8106014ec2dc108 (commit)
       via  6e2965abc46832a4970b80bce84a64d932426285 (commit)
       via  a8c3d59c520942c14434cea310c2c8a2fe623a9c (commit)
       via  2204a8d9305c85d2f7d65621a66443e7104c5f6b (commit)
       via  a084df558c2bb054140a2bea08c973fa76209b97 (commit)
       via  6c2355d82da1326a125ce7adcb8945a1d8efd671 (commit)
       via  60ee2fc214c9712b1db5ad82670eadc534279685 (commit)
       via  7ff006ea5351259abe8edc89520996513652c147 (commit)
       via  f2a79e0cc9bffcbe941d9a05b78f102fa6f09d03 (commit)
       via  eb95e18a3f2686762a99723ba4d7f0803f9d3c5d (commit)
       via  aba085a3abd65bc86075839298526ab2f686117c (commit)
       via  c88643983aeb511eca21e1d9e36b919a63482fb8 (commit)
       via  c1d564b0e5f95c54d822d39cf1715d93d293c70b (commit)
       via  d859cab46630d46aa1ae7b1d8de7ec92d0a4b8fa (commit)
       via  58838a7cd8e142ce12a90f6cafb80ea0c09797d5 (commit)
       via  be76fcdd9aa19fbf8982df2543685816a4afb1e0 (commit)
       via  2295b8b5c11c0177ff927d147800f6174feb4b9e (commit)
       via  2d8d861fadc8f3e0e7d5524c78f980dedc56f759 (commit)
       via  eb93b9b3b9d05c566f886b9a46bad4043d0a8534 (commit)
       via  02ce18b74c42b34a86208a713e00dfa0e0fe39de (commit)
       via  723ccdb54a0fc58c3e636481c404ea95b8f38d46 (commit)
       via  15eda5715c312d12ec24c24db80448bee90e38ea (commit)
       via  fbb9221d9de4c4a27e0c8aefc48c7c9c7a80ceab (commit)
       via  29659ffa9e00efe7a845aa303c70ba543c23174d (commit)
       via  18f8fa743346e5ac2ddc48dfdf6fdb4788c5b271 (commit)
      from  8843744ac700dd080333e8e1bcf6273e7fe273c3 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.


commit 9451dec1ace2370015b4c75367076cb5d4901f7e
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Thu Feb 8 18:16:53 2018 -0500

    12308: Propagate errors in Child().
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>

diff --git a/sdk/go/arvados/fs_base.go b/sdk/go/arvados/fs_base.go
index 4d22c1e..369b4bb 100644
--- a/sdk/go/arvados/fs_base.go
+++ b/sdk/go/arvados/fs_base.go
@@ -27,6 +27,7 @@ var (
 	ErrWriteOnlyMode     = errors.New("file is O_WRONLY")
 	ErrSyncNotSupported  = errors.New("O_SYNC flag is not supported")
 	ErrIsDirectory       = errors.New("cannot rename file to overwrite existing directory")
+	ErrNotADirectory     = errors.New("not a directory")
 	ErrPermission        = os.ErrPermission
 )
 
@@ -128,7 +129,7 @@ type inode interface {
 	// a child was added or changed, the new child is returned.
 	//
 	// Caller must have lock (or rlock if replace is nil).
-	Child(name string, replace func(inode) inode) inode
+	Child(name string, replace func(inode) (inode, error)) (inode, error)
 
 	sync.Locker
 	RLock()
@@ -202,8 +203,8 @@ func (*nullnode) Readdir() ([]os.FileInfo, error) {
 	return nil, ErrInvalidOperation
 }
 
-func (*nullnode) Child(name string, replace func(inode) inode) inode {
-	return nil
+func (*nullnode) Child(name string, replace func(inode) (inode, error)) (inode, error) {
+	return nil, ErrNotADirectory
 }
 
 type treenode struct {
@@ -236,18 +237,25 @@ func (n *treenode) IsDir() bool {
 	return true
 }
 
-func (n *treenode) Child(name string, replace func(inode) inode) (child inode) {
-	// TODO: special treatment for "", ".", ".."
+func (n *treenode) Child(name string, replace func(inode) (inode, error)) (child inode, err error) {
 	child = n.inodes[name]
-	if replace != nil {
-		newchild := replace(child)
-		if newchild == nil {
-			delete(n.inodes, name)
-		} else if newchild != child {
-			n.inodes[name] = newchild
-			n.fileinfo.modTime = time.Now()
-			child = newchild
-		}
+	if name == "" || name == "." || name == ".." {
+		err = ErrInvalidArgument
+		return
+	}
+	if replace == nil {
+		return
+	}
+	newchild, err := replace(child)
+	if err != nil {
+		return
+	}
+	if newchild == nil {
+		delete(n.inodes, name)
+	} else if newchild != child {
+		n.inodes[name] = newchild
+		n.fileinfo.modTime = time.Now()
+		child = newchild
 	}
 	return
 }
@@ -297,9 +305,9 @@ func (fs *fileSystem) openFile(name string, flag int, perm os.FileMode) (*fileha
 		return nil, ErrSyncNotSupported
 	}
 	dirname, name := path.Split(name)
-	parent := rlookup(fs.root, dirname)
-	if parent == nil {
-		return nil, os.ErrNotExist
+	parent, err := rlookup(fs.root, dirname)
+	if err != nil {
+		return nil, err
 	}
 	var readable, writable bool
 	switch flag & (os.O_RDWR | os.O_RDONLY | os.O_WRONLY) {
@@ -331,22 +339,26 @@ func (fs *fileSystem) openFile(name string, flag int, perm os.FileMode) (*fileha
 		parent.RLock()
 		defer parent.RUnlock()
 	}
-	n := parent.Child(name, nil)
-	if n == nil {
+	n, err := parent.Child(name, nil)
+	if err != nil {
+		return nil, err
+	} else if n == nil {
 		if !createMode {
 			return nil, os.ErrNotExist
 		}
-		var err error
-		n = parent.Child(name, func(inode) inode {
-			n, err = parent.FS().newNode(name, perm|0755, time.Now())
-			n.SetParent(parent, name)
-			return n
+		n, err = parent.Child(name, func(inode) (repl inode, err error) {
+			repl, err = parent.FS().newNode(name, perm|0755, time.Now())
+			if err != nil {
+				return
+			}
+			repl.SetParent(parent, name)
+			return
 		})
 		if err != nil {
 			return nil, err
 		} else if n == nil {
-			// parent rejected new child
-			return nil, ErrInvalidOperation
+			// Parent rejected new child, but returned no error
+			return nil, ErrInvalidArgument
 		}
 	} else if flag&os.O_EXCL != 0 {
 		return nil, ErrFileExists
@@ -375,38 +387,37 @@ func (fs *fileSystem) Create(name string) (File, error) {
 	return fs.OpenFile(name, os.O_CREATE|os.O_RDWR|os.O_TRUNC, 0)
 }
 
-func (fs *fileSystem) Mkdir(name string, perm os.FileMode) (err error) {
+func (fs *fileSystem) Mkdir(name string, perm os.FileMode) error {
 	dirname, name := path.Split(name)
-	n := rlookup(fs.root, dirname)
-	if n == nil {
-		return os.ErrNotExist
+	n, err := rlookup(fs.root, dirname)
+	if err != nil {
+		return err
 	}
 	n.Lock()
 	defer n.Unlock()
-	if n.Child(name, nil) != nil {
+	if child, err := n.Child(name, nil); err != nil {
+		return err
+	} else if child != nil {
 		return os.ErrExist
 	}
-	child := n.Child(name, func(inode) (child inode) {
-		child, err = n.FS().newNode(name, perm|os.ModeDir, time.Now())
-		child.SetParent(n, name)
+
+	_, err = n.Child(name, func(inode) (repl inode, err error) {
+		repl, err = n.FS().newNode(name, perm|os.ModeDir, time.Now())
+		if err != nil {
+			return
+		}
+		repl.SetParent(n, name)
 		return
 	})
-	if err != nil {
-		return err
-	} else if child == nil {
-		return ErrInvalidArgument
-	}
-	return nil
+	return err
 }
 
-func (fs *fileSystem) Stat(name string) (fi os.FileInfo, err error) {
-	node := rlookup(fs.root, name)
-	if node == nil {
-		err = os.ErrNotExist
-	} else {
-		fi = node.FileInfo()
+func (fs *fileSystem) Stat(name string) (os.FileInfo, error) {
+	node, err := rlookup(fs.root, name)
+	if err != nil {
+		return nil, err
 	}
-	return
+	return node.FileInfo(), nil
 }
 
 func (fs *fileSystem) Rename(oldname, newname string) error {
@@ -475,43 +486,31 @@ func (fs *fileSystem) Rename(oldname, newname string) error {
 		}
 	}
 
-	// Return ErrInvalidOperation if olddirf.inode doesn't even
-	// bother calling our "remove oldname entry" replacer func.
-	err = ErrInvalidArgument
-	olddirf.inode.Child(oldname, func(oldinode inode) inode {
-		err = nil
+	_, err = olddirf.inode.Child(oldname, func(oldinode inode) (inode, error) {
 		if oldinode == nil {
-			err = os.ErrNotExist
-			return nil
+			return oldinode, os.ErrNotExist
 		}
 		if locked[oldinode] {
 			// oldinode cannot become a descendant of itself.
-			err = ErrInvalidArgument
-			return oldinode
+			return oldinode, ErrInvalidArgument
 		}
 		if oldinode.FS() != cfs && newdirf.inode != olddirf.inode {
 			// moving a mount point to a different parent
 			// is not (yet) supported.
-			err = ErrInvalidArgument
-			return oldinode
+			return oldinode, ErrInvalidArgument
 		}
-		accepted := newdirf.inode.Child(newname, func(existing inode) inode {
+		accepted, err := newdirf.inode.Child(newname, func(existing inode) (inode, error) {
 			if existing != nil && existing.IsDir() {
-				err = ErrIsDirectory
-				return existing
+				return existing, ErrIsDirectory
 			}
-			return oldinode
+			return oldinode, nil
 		})
-		if accepted != oldinode {
-			if err == nil {
-				// newdirf didn't accept oldinode.
-				err = ErrInvalidArgument
-			}
+		if err != nil {
 			// Leave oldinode in olddir.
-			return oldinode
+			return oldinode, err
 		}
 		accepted.SetParent(newdirf.inode, newname)
-		return nil
+		return nil, nil
 	})
 	return err
 }
@@ -530,27 +529,25 @@ func (fs *fileSystem) RemoveAll(name string) error {
 	return err
 }
 
-func (fs *fileSystem) remove(name string, recursive bool) (err error) {
+func (fs *fileSystem) remove(name string, recursive bool) error {
 	dirname, name := path.Split(name)
 	if name == "" || name == "." || name == ".." {
 		return ErrInvalidArgument
 	}
-	dir := rlookup(fs.root, dirname)
-	if dir == nil {
-		return os.ErrNotExist
+	dir, err := rlookup(fs.root, dirname)
+	if err != nil {
+		return err
 	}
 	dir.Lock()
 	defer dir.Unlock()
-	dir.Child(name, func(node inode) inode {
+	_, err = dir.Child(name, func(node inode) (inode, error) {
 		if node == nil {
-			err = os.ErrNotExist
-			return nil
+			return nil, os.ErrNotExist
 		}
 		if !recursive && node.IsDir() && node.Size() > 0 {
-			err = ErrDirectoryNotEmpty
-			return node
+			return node, ErrDirectoryNotEmpty
 		}
-		return nil
+		return nil, nil
 	})
 	return err
 }
@@ -563,12 +560,9 @@ func (fs *fileSystem) Sync() error {
 // rlookup (recursive lookup) returns the inode for the file/directory
 // with the given name (which may contain "/" separators). If no such
 // file/directory exists, the returned node is nil.
-func rlookup(start inode, path string) (node inode) {
+func rlookup(start inode, path string) (node inode, err error) {
 	node = start
 	for _, name := range strings.Split(path, "/") {
-		if node == nil {
-			break
-		}
 		if node.IsDir() {
 			if name == "." || name == "" {
 				continue
@@ -578,11 +572,17 @@ func rlookup(start inode, path string) (node inode) {
 				continue
 			}
 		}
-		node = func() inode {
+		node, err = func() (inode, error) {
 			node.RLock()
 			defer node.RUnlock()
 			return node.Child(name, nil)
 		}()
+		if node == nil || err != nil {
+			break
+		}
+	}
+	if node == nil && err == nil {
+		err = os.ErrNotExist
 	}
 	return
 }
diff --git a/sdk/go/arvados/fs_collection.go b/sdk/go/arvados/fs_collection.go
index fbd9775..923615b 100644
--- a/sdk/go/arvados/fs_collection.go
+++ b/sdk/go/arvados/fs_collection.go
@@ -521,7 +521,7 @@ func (dn *dirnode) FS() FileSystem {
 	return dn.fs
 }
 
-func (dn *dirnode) Child(name string, replace func(inode) inode) inode {
+func (dn *dirnode) Child(name string, replace func(inode) (inode, error)) (inode, error) {
 	if dn == dn.fs.rootnode() && name == ".arvados#collection" {
 		gn := &getternode{Getter: func() ([]byte, error) {
 			var coll Collection
@@ -537,7 +537,7 @@ func (dn *dirnode) Child(name string, replace func(inode) inode) inode {
 			return data, err
 		}}
 		gn.SetParent(dn, name)
-		return gn
+		return gn, nil
 	}
 	return dn.treenode.Child(name, replace)
 }
@@ -837,38 +837,41 @@ func (dn *dirnode) createFileAndParents(path string) (fn *filenode, err error) {
 			node = node.Parent()
 			continue
 		}
-		node.Child(name, func(child inode) inode {
+		node, err = node.Child(name, func(child inode) (inode, error) {
 			if child == nil {
-				child, err = node.FS().newNode(name, 0755|os.ModeDir, node.Parent().FileInfo().ModTime())
+				child, err := node.FS().newNode(name, 0755|os.ModeDir, node.Parent().FileInfo().ModTime())
+				if err != nil {
+					return nil, err
+				}
 				child.SetParent(node, name)
-				node = child
+				return child, nil
 			} else if !child.IsDir() {
-				err = ErrFileExists
+				return child, ErrFileExists
 			} else {
-				node = child
+				return child, nil
 			}
-			return child
 		})
 		if err != nil {
 			return
 		}
 	}
-	node.Child(basename, func(child inode) inode {
+	_, err = node.Child(basename, func(child inode) (inode, error) {
 		switch child := child.(type) {
 		case nil:
 			child, err = node.FS().newNode(basename, 0755, node.FileInfo().ModTime())
+			if err != nil {
+				return nil, err
+			}
 			child.SetParent(node, basename)
 			fn = child.(*filenode)
-			return child
+			return child, nil
 		case *filenode:
 			fn = child
-			return child
+			return child, nil
 		case *dirnode:
-			err = ErrIsDirectory
-			return child
+			return child, ErrIsDirectory
 		default:
-			err = ErrInvalidArgument
-			return child
+			return child, ErrInvalidArgument
 		}
 	})
 	return
diff --git a/sdk/go/arvados/fs_collection_test.go b/sdk/go/arvados/fs_collection_test.go
index 023226f..8d32eb2 100644
--- a/sdk/go/arvados/fs_collection_test.go
+++ b/sdk/go/arvados/fs_collection_test.go
@@ -688,13 +688,13 @@ func (s *CollectionFSSuite) TestRename(c *check.C) {
 				err = fs.Rename(
 					fmt.Sprintf("dir%d/file%d/patherror", i, j),
 					fmt.Sprintf("dir%d/irrelevant", i))
-				c.Check(err, check.ErrorMatches, `.*does not exist`)
+				c.Check(err, check.ErrorMatches, `.*not a directory`)
 
 				// newname parent dir is a file
 				err = fs.Rename(
 					fmt.Sprintf("dir%d/dir%d/file%d", i, j, j),
 					fmt.Sprintf("dir%d/file%d/patherror", i, inner-j-1))
-				c.Check(err, check.ErrorMatches, `.*does not exist`)
+				c.Check(err, check.ErrorMatches, `.*not a directory`)
 			}(i, j)
 		}
 	}
diff --git a/sdk/go/arvados/fs_deferred.go b/sdk/go/arvados/fs_deferred.go
index 97fe68b..a84f64f 100644
--- a/sdk/go/arvados/fs_deferred.go
+++ b/sdk/go/arvados/fs_deferred.go
@@ -85,7 +85,7 @@ func (dn *deferrednode) Write(p []byte, pos filenodePtr) (int, filenodePtr, erro
 	return dn.realinode().Write(p, pos)
 }
 
-func (dn *deferrednode) Child(name string, replace func(inode) inode) inode {
+func (dn *deferrednode) Child(name string, replace func(inode) (inode, error)) (inode, error) {
 	return dn.realinode().Child(name, replace)
 }
 
diff --git a/sdk/go/arvados/fs_getternode.go b/sdk/go/arvados/fs_getternode.go
index c9ffb38..966fe9d 100644
--- a/sdk/go/arvados/fs_getternode.go
+++ b/sdk/go/arvados/fs_getternode.go
@@ -23,8 +23,8 @@ func (*getternode) IsDir() bool {
 	return false
 }
 
-func (*getternode) Child(string, func(inode) inode) inode {
-	return nil
+func (*getternode) Child(string, func(inode) (inode, error)) (inode, error) {
+	return nil, ErrInvalidArgument
 }
 
 func (gn *getternode) get() error {
diff --git a/sdk/go/arvados/fs_project.go b/sdk/go/arvados/fs_project.go
index f9cb799..a5e4710 100644
--- a/sdk/go/arvados/fs_project.go
+++ b/sdk/go/arvados/fs_project.go
@@ -5,7 +5,6 @@
 package arvados
 
 import (
-	"log"
 	"os"
 	"sync"
 )
@@ -48,8 +47,8 @@ func (pn *projectnode) setup() {
 			if coll.Name == "" {
 				continue
 			}
-			pn.inode.Child(coll.Name, func(inode) inode {
-				return deferredCollectionFS(fs, pn, coll)
+			pn.inode.Child(coll.Name, func(inode) (inode, error) {
+				return deferredCollectionFS(fs, pn, coll), nil
 			})
 		}
 		params.Filters = append(filters, Filter{"uuid", ">", resp.Items[len(resp.Items)-1].UUID})
@@ -71,8 +70,8 @@ func (pn *projectnode) setup() {
 			if group.Name == "" || group.Name == "." || group.Name == ".." {
 				continue
 			}
-			pn.inode.Child(group.Name, func(inode) inode {
-				return fs.newProjectNode(pn, group.Name, group.UUID)
+			pn.inode.Child(group.Name, func(inode) (inode, error) {
+				return fs.newProjectNode(pn, group.Name, group.UUID), nil
 			})
 		}
 		params.Filters = append(filters, Filter{"uuid", ">", resp.Items[len(resp.Items)-1].UUID})
@@ -87,30 +86,35 @@ func (pn *projectnode) Readdir() ([]os.FileInfo, error) {
 	return pn.inode.Readdir()
 }
 
-func (pn *projectnode) Child(name string, replace func(inode) inode) inode {
+func (pn *projectnode) Child(name string, replace func(inode) (inode, error)) (inode, error) {
 	pn.setupOnce.Do(pn.setup)
 	if pn.err != nil {
-		log.Printf("BUG: not propagating error setting up %T %v: %s", pn, pn, pn.err)
-		// TODO: propagate error, instead of just being empty
-		return nil
+		return nil, pn.err
 	}
 	if replace == nil {
 		// lookup
 		return pn.inode.Child(name, nil)
 	}
-	return pn.inode.Child(name, func(existing inode) inode {
-		if repl := replace(existing); repl == nil {
-			// delete
+	return pn.inode.Child(name, func(existing inode) (inode, error) {
+		if repl, err := replace(existing); err != nil {
+			return existing, err
+		} else if repl == nil {
+			if existing == nil {
+				return nil, nil
+			}
+			// rmdir
 			// (TODO)
-			return pn.Child(name, nil) // not implemented
+			return existing, ErrInvalidArgument
+		} else if existing != nil {
+			// clobber
+			return existing, ErrInvalidArgument
 		} else if repl.FileInfo().IsDir() {
 			// mkdir
 			// TODO: repl.SetParent(pn, name), etc.
-			return pn.Child(name, nil) // not implemented
+			return existing, ErrInvalidArgument
 		} else {
 			// create file
-			// TODO: repl.SetParent(pn, name), etc.
-			return pn.Child(name, nil) // not implemented
+			return existing, ErrInvalidArgument
 		}
 	})
 }
diff --git a/sdk/go/arvados/fs_site.go b/sdk/go/arvados/fs_site.go
index c8d7360..701711e 100644
--- a/sdk/go/arvados/fs_site.go
+++ b/sdk/go/arvados/fs_site.go
@@ -37,7 +37,7 @@ func (c *Client) SiteFileSystem(kc keepClient) FileSystem {
 		},
 		inodes: make(map[string]inode),
 	}
-	root.inode.Child("by_id", func(inode) inode {
+	root.inode.Child("by_id", func(inode) (inode, error) {
 		return &vdirnode{
 			inode: &treenode{
 				fs:     fs,
@@ -50,10 +50,10 @@ func (c *Client) SiteFileSystem(kc keepClient) FileSystem {
 				},
 			},
 			create: fs.mountCollection,
-		}
+		}, nil
 	})
-	root.inode.Child("home", func(inode) inode {
-		return fs.newProjectNode(fs.root, "home", "")
+	root.inode.Child("home", func(inode) (inode, error) {
+		return fs.newProjectNode(fs.root, "home", ""), nil
 	})
 	return fs
 }
@@ -104,18 +104,23 @@ type vdirnode struct {
 	create func(parent inode, name string) inode
 }
 
-func (vn *vdirnode) Child(name string, _ func(inode) inode) inode {
-	return vn.inode.Child(name, func(existing inode) inode {
-		if existing != nil {
-			return existing
-		} else if vn.create == nil {
-			return nil
+func (vn *vdirnode) Child(name string, replace func(inode) (inode, error)) (inode, error) {
+	return vn.inode.Child(name, func(existing inode) (inode, error) {
+		if existing == nil && vn.create != nil {
+			existing = vn.create(vn, name)
+			if existing != nil {
+				existing.SetParent(vn, name)
+				vn.inode.(*treenode).fileinfo.modTime = time.Now()
+			}
 		}
-		n := vn.create(vn, name)
-		if n != nil {
-			n.SetParent(vn, name)
-			vn.inode.(*treenode).fileinfo.modTime = time.Now()
+		if replace == nil {
+			return existing, nil
+		} else if tryRepl, err := replace(existing); err != nil {
+			return existing, err
+		} else if tryRepl != existing {
+			return existing, ErrInvalidArgument
+		} else {
+			return existing, nil
 		}
-		return n
 	})
 }

commit d1ac0920b9f8c4b793cf33a7016c1dfad4ffba10
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Thu Feb 8 16:29:40 2018 -0500

    12308: Propagate errors in Readdir().
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>

diff --git a/sdk/go/arvados/fs_base.go b/sdk/go/arvados/fs_base.go
index 6402a8e..4d22c1e 100644
--- a/sdk/go/arvados/fs_base.go
+++ b/sdk/go/arvados/fs_base.go
@@ -96,7 +96,7 @@ type inode interface {
 	Write([]byte, filenodePtr) (int, filenodePtr, error)
 	Truncate(int64) error
 	IsDir() bool
-	Readdir() []os.FileInfo
+	Readdir() ([]os.FileInfo, error)
 	Size() int64
 	FileInfo() os.FileInfo
 
@@ -198,8 +198,8 @@ func (*nullnode) IsDir() bool {
 	return false
 }
 
-func (*nullnode) Readdir() []os.FileInfo {
-	return nil
+func (*nullnode) Readdir() ([]os.FileInfo, error) {
+	return nil, ErrInvalidOperation
 }
 
 func (*nullnode) Child(name string, replace func(inode) inode) inode {
@@ -263,7 +263,7 @@ func (n *treenode) FileInfo() os.FileInfo {
 	return n.fileinfo
 }
 
-func (n *treenode) Readdir() (fi []os.FileInfo) {
+func (n *treenode) Readdir() (fi []os.FileInfo, err error) {
 	n.RLock()
 	defer n.RUnlock()
 	fi = make([]os.FileInfo, 0, len(n.inodes))
diff --git a/sdk/go/arvados/fs_deferred.go b/sdk/go/arvados/fs_deferred.go
index e638838..97fe68b 100644
--- a/sdk/go/arvados/fs_deferred.go
+++ b/sdk/go/arvados/fs_deferred.go
@@ -89,15 +89,15 @@ func (dn *deferrednode) Child(name string, replace func(inode) inode) inode {
 	return dn.realinode().Child(name, replace)
 }
 
-func (dn *deferrednode) Truncate(size int64) error      { return dn.realinode().Truncate(size) }
-func (dn *deferrednode) SetParent(p inode, name string) { dn.realinode().SetParent(p, name) }
-func (dn *deferrednode) IsDir() bool                    { return dn.currentinode().IsDir() }
-func (dn *deferrednode) Readdir() []os.FileInfo         { return dn.realinode().Readdir() }
-func (dn *deferrednode) Size() int64                    { return dn.currentinode().Size() }
-func (dn *deferrednode) FileInfo() os.FileInfo          { return dn.currentinode().FileInfo() }
-func (dn *deferrednode) Lock()                          { dn.realinode().Lock() }
-func (dn *deferrednode) Unlock()                        { dn.realinode().Unlock() }
-func (dn *deferrednode) RLock()                         { dn.realinode().RLock() }
-func (dn *deferrednode) RUnlock()                       { dn.realinode().RUnlock() }
-func (dn *deferrednode) FS() FileSystem                 { return dn.currentinode().FS() }
-func (dn *deferrednode) Parent() inode                  { return dn.currentinode().Parent() }
+func (dn *deferrednode) Truncate(size int64) error       { return dn.realinode().Truncate(size) }
+func (dn *deferrednode) SetParent(p inode, name string)  { dn.realinode().SetParent(p, name) }
+func (dn *deferrednode) IsDir() bool                     { return dn.currentinode().IsDir() }
+func (dn *deferrednode) Readdir() ([]os.FileInfo, error) { return dn.realinode().Readdir() }
+func (dn *deferrednode) Size() int64                     { return dn.currentinode().Size() }
+func (dn *deferrednode) FileInfo() os.FileInfo           { return dn.currentinode().FileInfo() }
+func (dn *deferrednode) Lock()                           { dn.realinode().Lock() }
+func (dn *deferrednode) Unlock()                         { dn.realinode().Unlock() }
+func (dn *deferrednode) RLock()                          { dn.realinode().RLock() }
+func (dn *deferrednode) RUnlock()                        { dn.realinode().RUnlock() }
+func (dn *deferrednode) FS() FileSystem                  { return dn.currentinode().FS() }
+func (dn *deferrednode) Parent() inode                   { return dn.currentinode().Parent() }
diff --git a/sdk/go/arvados/fs_filehandle.go b/sdk/go/arvados/fs_filehandle.go
index d586531..127bee8 100644
--- a/sdk/go/arvados/fs_filehandle.go
+++ b/sdk/go/arvados/fs_filehandle.go
@@ -74,10 +74,14 @@ func (f *filehandle) Readdir(count int) ([]os.FileInfo, error) {
 		return nil, ErrInvalidOperation
 	}
 	if count <= 0 {
-		return f.inode.Readdir(), nil
+		return f.inode.Readdir()
 	}
 	if f.unreaddirs == nil {
-		f.unreaddirs = f.inode.Readdir()
+		var err error
+		f.unreaddirs, err = f.inode.Readdir()
+		if err != nil {
+			return nil, err
+		}
 	}
 	if len(f.unreaddirs) == 0 {
 		return nil, io.EOF
diff --git a/sdk/go/arvados/fs_project.go b/sdk/go/arvados/fs_project.go
index 4dd8699..f9cb799 100644
--- a/sdk/go/arvados/fs_project.go
+++ b/sdk/go/arvados/fs_project.go
@@ -79,8 +79,11 @@ func (pn *projectnode) setup() {
 	}
 }
 
-func (pn *projectnode) Readdir() []os.FileInfo {
+func (pn *projectnode) Readdir() ([]os.FileInfo, error) {
 	pn.setupOnce.Do(pn.setup)
+	if pn.err != nil {
+		return nil, pn.err
+	}
 	return pn.inode.Readdir()
 }
 

commit 50b3e54b41ada32f84b154b35f7b02b6c0217c8e
Merge: 0faa784 acb392d
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Thu Feb 8 14:41:05 2018 -0500

    12308: Merge branch 'master' into 12308-go-fuse
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>


commit 0faa78426b42eb7cb40822c0963b15f07c1aa9cf
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Thu Feb 1 09:45:47 2018 -0500

    12308: Add spying client for testing deferred loading.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>

diff --git a/sdk/go/arvados/fs_project_test.go b/sdk/go/arvados/fs_project_test.go
index 92d8672..1de0714 100644
--- a/sdk/go/arvados/fs_project_test.go
+++ b/sdk/go/arvados/fs_project_test.go
@@ -5,11 +5,38 @@
 package arvados
 
 import (
+	"bytes"
+	"encoding/json"
+	"io"
 	"os"
 
 	check "gopkg.in/check.v1"
 )
 
+type spiedRequest struct {
+	method string
+	path   string
+	params map[string]interface{}
+}
+
+type spyingClient struct {
+	*Client
+	calls []spiedRequest
+}
+
+func (sc *spyingClient) RequestAndDecode(dst interface{}, method, path string, body io.Reader, params interface{}) error {
+	var paramsCopy map[string]interface{}
+	var buf bytes.Buffer
+	json.NewEncoder(&buf).Encode(params)
+	json.NewDecoder(&buf).Decode(&paramsCopy)
+	sc.calls = append(sc.calls, spiedRequest{
+		method: method,
+		path:   path,
+		params: paramsCopy,
+	})
+	return sc.Client.RequestAndDecode(dst, method, path, body, params)
+}
+
 func (s *SiteFSSuite) TestHomeProject(c *check.C) {
 	f, err := s.fs.Open("/home")
 	c.Assert(err, check.IsNil)

commit bb141976709b75a8b8cdf3135fc1d73e22e7ba72
Author: Tom Clegg <tclegg at veritasgenetics.com>
Date:   Thu Feb 1 09:37:31 2018 -0500

    12308: Add /home test case.
    
    Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tclegg at veritasgenetics.com>

diff --git a/sdk/go/arvados/fs_project_test.go b/sdk/go/arvados/fs_project_test.go
new file mode 100644
index 0000000..92d8672
--- /dev/null
+++ b/sdk/go/arvados/fs_project_test.go
@@ -0,0 +1,51 @@
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: Apache-2.0
+
+package arvados
+
+import (
+	"os"
+
+	check "gopkg.in/check.v1"
+)
+
+func (s *SiteFSSuite) TestHomeProject(c *check.C) {
+	f, err := s.fs.Open("/home")
+	c.Assert(err, check.IsNil)
+	fis, err := f.Readdir(-1)
+	c.Check(len(fis), check.Not(check.Equals), 0)
+
+	ok := false
+	for _, fi := range fis {
+		c.Check(fi.Name(), check.Not(check.Equals), "")
+		if fi.Name() == "Unrestricted public data" {
+			ok = true
+		}
+	}
+	c.Check(ok, check.Equals, true)
+
+	f, err = s.fs.Open("/home/Unrestricted public data/..")
+	c.Assert(err, check.IsNil)
+	fi, err := f.Stat()
+	c.Check(err, check.IsNil)
+	c.Check(fi.IsDir(), check.Equals, true)
+	c.Check(fi.Name(), check.Equals, "home")
+
+	f, err = s.fs.Open("/home/Unrestricted public data/Subproject in anonymous accessible project")
+	c.Check(err, check.IsNil)
+	fi, err = f.Stat()
+	c.Check(err, check.IsNil)
+	c.Check(fi.IsDir(), check.Equals, true)
+
+	for _, nx := range []string{
+		"/home/A Project",
+		"/home/A Project/does not exist",
+		"/home/Unrestricted public data/does not exist",
+	} {
+		c.Log(nx)
+		f, err = s.fs.Open(nx)
+		c.Check(err, check.NotNil)
+		c.Check(os.IsNotExist(err), check.Equals, true)
+	}
+}

-----------------------------------------------------------------------


hooks/post-receive
-- 




More information about the arvados-commits mailing list