2 # Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file.
6 """Tests of a network memoizer."""
14 sys.path.append(os.path.join(os.path.dirname(__file__), '..'))
15 import pynacl.directory_storage
16 import pynacl.fake_storage
17 import pynacl.file_tools
18 import pynacl.gsd_storage
19 import pynacl.working_directory
25 class TestOnce(unittest.TestCase):
27 def GenerateTestData(self, noise, work_dir):
29 self._input_files = []
31 dir_name = os.path.join(work_dir, noise + 'input%d_dir' % i)
33 filename = os.path.join(dir_name, 'in%d' % i)
34 pynacl.file_tools.WriteFile(noise + 'data%d' % i, filename)
35 self._input_dirs['input%d' % i] = dir_name
36 self._input_files.append(filename)
37 self._output_dirs = []
38 self._output_files = []
40 dir_name = os.path.join(work_dir, noise + 'output%d_dir' % i)
42 filename = os.path.join(dir_name, 'out')
43 self._output_dirs.append(dir_name)
44 self._output_files.append(filename)
46 def test_FirstTime(self):
47 # Test that the computation is always performed if the cache is empty.
48 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
49 self.GenerateTestData('FirstTime', work_dir)
50 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
51 system_summary='test')
52 o.Run('test', self._input_dirs, self._output_dirs[0],
53 [command.Copy('%(input0)s/in0', '%(output)s/out')])
54 self.assertEquals('FirstTimedata0',
55 pynacl.file_tools.ReadFile(self._output_files[0]))
57 def test_HitsCacheSecondTime(self):
58 # Test that the computation is not performed on a second instance.
59 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
60 self.GenerateTestData('HitsCacheSecondTime', work_dir)
62 def Copy(logger, subst, src, dst):
64 shutil.copyfile(subst.SubstituteAbsPaths(src),
65 subst.SubstituteAbsPaths(dst))
69 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
70 print_url=stash_url, system_summary='test')
71 o.Run('test', self._input_dirs, self._output_dirs[0],
72 [command.Runnable(None, Copy,'%(input0)s/in0', '%(output)s/out')])
73 initial_url = self._url
75 o.Run('test', self._input_dirs, self._output_dirs[1],
76 [command.Runnable(None, Copy,'%(input0)s/in0', '%(output)s/out')])
77 self.assertEquals(pynacl.file_tools.ReadFile(self._input_files[0]),
78 pynacl.file_tools.ReadFile(self._output_files[0]))
79 self.assertEquals(pynacl.file_tools.ReadFile(self._input_files[0]),
80 pynacl.file_tools.ReadFile(self._output_files[1]))
81 self.assertEquals(1, self._tally)
82 self.assertEquals(initial_url, self._url)
84 def test_CachedCommandRecorded(self):
85 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
86 self.GenerateTestData('CachedCommand', work_dir)
87 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
88 system_summary='test')
89 o.Run('test', self._input_dirs, self._output_dirs[0],
90 [command.Copy('%(input0)s/in0', '%(output)s/out')])
91 self.assertEquals(len(o.GetCachedCloudItems()), 1)
93 def test_UncachedCommandsNotRecorded(self):
94 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
95 self.GenerateTestData('CachedCommand', work_dir)
96 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
97 system_summary='test', cache_results=False)
98 o.Run('test', self._input_dirs, self._output_dirs[0],
99 [command.Copy('%(input0)s/in0', '%(output)s/out')])
100 self.assertEquals(len(o.GetCachedCloudItems()), 0)
102 def FileLength(self, src, dst, **kwargs):
103 """Command object to write the length of one file into another."""
104 return command.Command([
105 sys.executable, '-c',
106 'import sys; open(sys.argv[2], "wb").write('
107 'str(len(open(sys.argv[1], "rb").read())))', src, dst
110 def test_RecomputeHashMatches(self):
111 # Test that things don't get stored to the output cache if they exist
113 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
114 # Setup test data in input0, input1 using memory storage.
115 self.GenerateTestData('RecomputeHashMatches', work_dir)
116 fs = pynacl.fake_storage.FakeStorage()
117 o = once.Once(storage=fs, system_summary='test')
119 # Run the computation (compute the length of a file) from input0 to
121 o.Run('test', self._input_dirs, self._output_dirs[0],
123 '%(input0)s/in0', '%(output)s/out')])
125 # Check that 3 writes have occurred. One to write a mapping from in->out,
126 # one for the output data, and one for the log file.
127 self.assertEquals(3, fs.WriteCount())
129 # Run the computation again from input1 to output1.
130 # (These should have the same length.)
131 o.Run('test', self._input_dirs, self._output_dirs[1],
133 '%(input1)s/in1', '%(output)s/out')])
135 # Write count goes up by one as an in->out hash is added,
136 # but no new output is stored (as it is the same).
137 self.assertEquals(4, fs.WriteCount())
139 # Check that the test is still valid:
140 # - in0 and in1 have equal length.
141 # - out0 and out1 have that length in them.
142 # - out0 and out1 agree.
144 str(len(pynacl.file_tools.ReadFile(self._input_files[0]))),
145 pynacl.file_tools.ReadFile(self._output_files[0])
148 str(len(pynacl.file_tools.ReadFile(self._input_files[1]))),
149 pynacl.file_tools.ReadFile(self._output_files[1])
152 pynacl.file_tools.ReadFile(self._output_files[0]),
153 pynacl.file_tools.ReadFile(self._output_files[1])
156 def test_FailsWhenWritingFails(self):
157 # Check that once doesn't eat the storage layer failures for writes.
158 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
159 self.GenerateTestData('FailsWhenWritingFails', work_dir)
160 def call(cmd, **kwargs):
161 # Cause gsutil commands to fail.
163 bad_storage = pynacl.gsd_storage.GSDStorage(
165 write_bucket='mybucket',
168 o = once.Once(storage=bad_storage, system_summary='test')
169 self.assertRaises(pynacl.gsd_storage.GSDStorageError, o.Run, 'test',
170 self._input_dirs, self._output_dirs[0],
171 [command.Copy('%(input0)s/in0', '%(output)s/out')])
173 def test_UseCachedResultsFalse(self):
174 # Check that the use_cached_results=False does indeed cause computations
175 # to be redone, even when present in the cache.
176 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
177 self.GenerateTestData('UseCachedResultsFalse', work_dir)
179 def Copy(logger, subst, src, dst):
181 shutil.copyfile(subst.SubstituteAbsPaths(src),
182 subst.SubstituteAbsPaths(dst))
183 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
184 use_cached_results=False,
185 system_summary='test')
186 o.Run('test', self._input_dirs, self._output_dirs[0],
187 [command.Runnable(None, Copy,'%(input0)s/in0', '%(output)s/out')])
188 o.Run('test', self._input_dirs, self._output_dirs[1],
189 [command.Runnable(None, Copy,'%(input0)s/in0', '%(output)s/out')])
190 self.assertEquals(2, self._tally)
191 self.assertEquals(pynacl.file_tools.ReadFile(self._input_files[0]),
192 pynacl.file_tools.ReadFile(self._output_files[0]))
193 self.assertEquals(pynacl.file_tools.ReadFile(self._input_files[0]),
194 pynacl.file_tools.ReadFile(self._output_files[1]))
196 def test_CacheResultsFalse(self):
197 # Check that setting cache_results=False prevents results from being written
199 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
200 self.GenerateTestData('CacheResultsFalse', work_dir)
201 storage = pynacl.fake_storage.FakeStorage()
202 o = once.Once(storage=storage, cache_results=False, system_summary='test')
203 o.Run('test', self._input_dirs, self._output_dirs[0],
204 [command.Copy('%(input0)s/in0', '%(output)s/out')])
205 self.assertEquals(0, storage.ItemCount())
206 self.assertEquals(pynacl.file_tools.ReadFile(self._input_files[0]),
207 pynacl.file_tools.ReadFile(self._output_files[0]))
209 def test_Mkdir(self):
210 # Test the Mkdir convenience wrapper works.
211 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
212 self.GenerateTestData('Mkdir', work_dir)
213 foo = os.path.join(work_dir, 'foo')
214 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
215 cache_results=False, system_summary='test')
216 o.Run('test', self._input_dirs, foo,
217 [command.Mkdir('%(output)s/hi')])
218 self.assertTrue(os.path.isdir(os.path.join(foo, 'hi')))
220 def test_Command(self):
221 # Test a plain command.
222 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
223 self.GenerateTestData('Command', work_dir)
224 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
225 system_summary='test')
226 o.Run('test', self._input_dirs, self._output_dirs[0],
228 sys.executable, '-c',
229 'import sys; open(sys.argv[1], "wb").write("hello")',
233 pynacl.file_tools.ReadFile(self._output_files[0])
236 def test_NumCores(self):
237 # Test that the core count is substituted. Since we don't know how many
238 # cores the test machine will have, just check that it's an integer.
239 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
240 self.GenerateTestData('NumCores', work_dir)
241 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
242 system_summary='test')
243 def CheckCores(logger, subst):
244 self.assertNotEquals(0, int(subst.Substitute('%(cores)s')))
245 o.Run('test', {}, self._output_dirs[0], [command.Runnable(None,
248 def test_RunConditionsFalse(self):
249 # Test that a command uses run conditions to decide whether or not to run.
250 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
251 self.GenerateTestData('Command', work_dir)
252 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
253 system_summary='test')
254 o.Run('test', self._input_dirs, self._output_dirs[0],
256 sys.executable, '-c',
257 'import sys; open(sys.argv[1], "wb").write("hello")',
259 run_cond=lambda cmd_opts: True),
261 sys.executable, '-c',
262 'import sys; open(sys.argv[1], "wb").write("not hello")',
264 run_cond=lambda cmd_opts: False)])
267 pynacl.file_tools.ReadFile(self._output_files[0])
270 def test_OutputsFlushPathHashCache(self):
271 # Test that commands that output to a directory that has an input hash
272 # value cached raise an error indicating an input output cycle.
273 with pynacl.working_directory.TemporaryWorkingDirectory() as work_dir:
274 self.GenerateTestData('CacheFlush', work_dir)
275 o = once.Once(storage=pynacl.fake_storage.FakeStorage(),
276 system_summary='test')
278 once.UserError, o.Run,
279 'test', self._input_dirs, self._input_dirs['input0'],
280 [command.Copy('%(input0)s/in0', '%(output)s/out')])
283 if __name__ == '__main__':