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