1 # Copyright (C) The Arvados Authors. All rights reserved.
3 # SPDX-License-Identifier: Apache-2.0
15 import arvados.collection
17 import arvados_cwl.executor
19 from cwltool.pathmapper import MapperEnt
20 from .mock_discovery import get_rootDesc
22 from arvados_cwl.pathmapper import ArvPathMapper
24 def upload_mock(files, api, dry_run=False, num_retries=0, project=None, fnPattern="$(file %s/%s)", name=None, collection=None, packed=None):
25 pdh = "99999999999999999999999999999991+99"
27 c.keepref = "%s/%s" % (pdh, os.path.basename(c.fn))
28 c.fn = fnPattern % (pdh, os.path.basename(c.fn))
30 class TestPathmap(unittest.TestCase):
32 self.api = mock.MagicMock()
33 self.api._rootDesc = get_rootDesc()
35 def test_keepref(self):
36 """Test direct keep references."""
38 arvrunner = arvados_cwl.executor.ArvCwlExecutor(self.api)
40 p = ArvPathMapper(arvrunner, [{
42 "location": "keep:99999999999999999999999999999991+99/hw.py"
43 }], "", "/test/%s", "/test/%s/%s")
45 self.assertEqual({'keep:99999999999999999999999999999991+99/hw.py': MapperEnt(resolved='keep:99999999999999999999999999999991+99/hw.py', target='/test/99999999999999999999999999999991+99/hw.py', type='File', staged=True)},
48 @mock.patch("arvados.commands.run.uploadfiles")
49 @mock.patch("arvados.commands.run.statfile")
50 def test_upload(self, statfile, upl):
51 """Test pathmapper uploading files."""
53 arvrunner = arvados_cwl.executor.ArvCwlExecutor(self.api)
55 def statfile_mock(prefix, fn, fnPattern="$(file %s/%s)", dirPattern="$(dir %s/%s/)", raiseOSError=False):
56 st = arvados.commands.run.UploadFile("", "tests/hw.py")
59 upl.side_effect = upload_mock
60 statfile.side_effect = statfile_mock
62 p = ArvPathMapper(arvrunner, [{
64 "location": "file:tests/hw.py"
65 }], "", "/test/%s", "/test/%s/%s")
67 self.assertEqual({'file:tests/hw.py': MapperEnt(resolved='keep:99999999999999999999999999999991+99/hw.py', target='/test/99999999999999999999999999999991+99/hw.py', type='File', staged=True)},
70 @mock.patch("arvados.commands.run.uploadfiles")
71 @mock.patch("arvados.commands.run.statfile")
72 def test_statfile(self, statfile, upl):
73 """Test pathmapper handling ArvFile references."""
74 arvrunner = arvados_cwl.executor.ArvCwlExecutor(self.api)
76 # An ArvFile object returned from arvados.commands.run.statfile means the file is located on a
77 # keep mount, so we can construct a direct reference directly without upload.
78 def statfile_mock(prefix, fn, fnPattern="$(file %s/%s)", dirPattern="$(dir %s/%s/)", raiseOSError=False):
79 st = arvados.commands.run.ArvFile("", fnPattern % ("99999999999999999999999999999991+99", "hw.py"))
82 upl.side_effect = upload_mock
83 statfile.side_effect = statfile_mock
85 p = ArvPathMapper(arvrunner, [{
87 "location": "file:tests/hw.py"
88 }], "", "/test/%s", "/test/%s/%s")
90 self.assertEqual({'file:tests/hw.py': MapperEnt(resolved='keep:99999999999999999999999999999991+99/hw.py', target='/test/99999999999999999999999999999991+99/hw.py', type='File', staged=True)},
93 @mock.patch("os.stat")
94 def test_missing_file(self, stat):
95 """Test pathmapper handling missing references."""
96 arvrunner = arvados_cwl.executor.ArvCwlExecutor(self.api)
98 stat.side_effect = OSError(2, "No such file or directory")
100 with self.assertRaises(OSError):
101 p = ArvPathMapper(arvrunner, [{
103 "location": "file:tests/hw.py"
104 }], "", "/test/%s", "/test/%s/%s")
106 def test_needs_new_collection(self):
107 arvrunner = arvados_cwl.executor.ArvCwlExecutor(self.api)
109 # Plain file. Don't need a new collection.
112 "location": "keep:99999999999999999999999999999991+99/hw.py",
115 p = ArvPathMapper(arvrunner, [], "", "%s", "%s/%s")
116 p._pathmap["keep:99999999999999999999999999999991+99/hw.py"] = True
117 self.assertFalse(p.needs_new_collection(a))
119 # A file that isn't in the pathmap (for some reason). Need a new collection.
120 p = ArvPathMapper(arvrunner, [], "", "%s", "%s/%s")
121 self.assertTrue(p.needs_new_collection(a))
123 # A file with a secondary file in the same collection. Don't need
127 "location": "keep:99999999999999999999999999999991+99/hw.py",
131 "location": "keep:99999999999999999999999999999991+99/hw.pyc",
135 p = ArvPathMapper(arvrunner, [], "", "%s", "%s/%s")
136 p._pathmap["keep:99999999999999999999999999999991+99/hw.py"] = True
137 p._pathmap["keep:99999999999999999999999999999991+99/hw.pyc"] = True
138 self.assertFalse(p.needs_new_collection(a))
140 # Secondary file is in a different collection from the
141 # a new collectionprimary. Need a new collection.
144 "location": "keep:99999999999999999999999999999991+99/hw.py",
148 "location": "keep:99999999999999999999999999999992+99/hw.pyc",
152 p = ArvPathMapper(arvrunner, [], "", "%s", "%s/%s")
153 p._pathmap["keep:99999999999999999999999999999991+99/hw.py"] = True
154 p._pathmap["keep:99999999999999999999999999999992+99/hw.pyc"] = True
155 self.assertTrue(p.needs_new_collection(a))
157 # Secondary file should be staged to a different name than
158 # path in location. Need a new collection.
161 "location": "keep:99999999999999999999999999999991+99/hw.py",
165 "location": "keep:99999999999999999999999999999991+99/hw.pyc",
166 "basename": "hw.other"
169 p = ArvPathMapper(arvrunner, [], "", "%s", "%s/%s")
170 p._pathmap["keep:99999999999999999999999999999991+99/hw.py"] = True
171 p._pathmap["keep:99999999999999999999999999999991+99/hw.pyc"] = True
172 self.assertTrue(p.needs_new_collection(a))
174 # Secondary file is a directory. Do not need a new collection.
177 "location": "keep:99999999999999999999999999999991+99/hw.py",
180 "class": "Directory",
181 "location": "keep:99999999999999999999999999999991+99/hw",
185 "location": "keep:99999999999999999999999999999991+99/hw/h2",
190 p = ArvPathMapper(arvrunner, [], "", "%s", "%s/%s")
191 p._pathmap["keep:99999999999999999999999999999991+99/hw.py"] = True
192 p._pathmap["keep:99999999999999999999999999999991+99/hw"] = True
193 p._pathmap["keep:99999999999999999999999999999991+99/hw/h2"] = True
194 self.assertFalse(p.needs_new_collection(a))
196 # Secondary file is a renamed directory. Need a new collection.
199 "location": "keep:99999999999999999999999999999991+99/hw.py",
202 "class": "Directory",
203 "location": "keep:99999999999999999999999999999991+99/hw",
207 "location": "keep:99999999999999999999999999999991+99/hw/h2",
212 p = ArvPathMapper(arvrunner, [], "", "%s", "%s/%s")
213 p._pathmap["keep:99999999999999999999999999999991+99/hw.py"] = True
214 p._pathmap["keep:99999999999999999999999999999991+99/hw"] = True
215 p._pathmap["keep:99999999999999999999999999999991+99/hw/h2"] = True
216 self.assertTrue(p.needs_new_collection(a))
218 # Secondary file is a file literal. Need a new collection.
221 "location": "keep:99999999999999999999999999999991+99/hw.py",
226 "basename": "hw.pyc",
230 p = ArvPathMapper(arvrunner, [], "", "%s", "%s/%s")
231 p._pathmap["keep:99999999999999999999999999999991+99/hw.py"] = True
232 p._pathmap["_:123"] = True
233 self.assertTrue(p.needs_new_collection(a))