def test_fresh_output_with_used_input(self): def fake_getctime(path: str): if path.startswith("read"): return 100 if path.startswith("write"): return 200 return 0 used_input = "read.me" written_output = "write.me" with mock.patch.object(os.path, 'exists', return_value=True) as mock_exists: with mock.patch.object(os.path, 'getctime', wraps=fake_getctime) as mock_ctime: output_diagnostics = action_tracer.diagnose_stale_outputs( accesses=[ action_tracer.Read(used_input), action_tracer.Write(written_output), ], access_constraints=action_tracer.AccessConstraints( allowed_reads={used_input}, required_writes={written_output}), ) # There are no untouched outputs, so getctime is never called. mock_exists.assert_not_called() mock_ctime.assert_not_called() self.assertEqual( output_diagnostics, action_tracer.StalenessDiagnostics( required_writes={written_output}, # newest_input is not evaluated stale_outputs=set(), ), )
def test_stale_output_with_used_input(self): def fake_read_ctime(path: str): if path.startswith("read"): return 200 raise ValueError(f'Unexpected path: {path}') def fake_write_ctime(path: str): if path.startswith("write"): return 100 raise ValueError(f'Unexpected path: {path}') used_input = "read.me" required_writes = {"write.me"} with mock.patch.object(os.path, 'exists', return_value=True) as mock_exists: with mock.patch.object(os.path, 'getctime', wraps=fake_read_ctime) as mock_read_ctime: with mock.patch.object( action_tracer, 'realpath_ctime', wraps=fake_write_ctime) as mock_write_ctime: output_diagnostics = action_tracer.diagnose_stale_outputs( accesses=[action_tracer.Read(used_input)], access_constraints=action_tracer.AccessConstraints( allowed_reads={used_input}, required_writes=required_writes), ) mock_exists.assert_called_once() mock_read_ctime.assert_called() mock_write_ctime.assert_called() self.assertEqual( output_diagnostics, action_tracer.StalenessDiagnostics(required_writes=required_writes, newest_input=used_input, stale_outputs={"write.me"}), )
def test_no_accesses_no_constraints(self): output_diagnostics = action_tracer.diagnose_stale_outputs( accesses=[], access_constraints=action_tracer.AccessConstraints(), ) self.assertEqual( output_diagnostics, action_tracer.StalenessDiagnostics(), )
def test_missing_write_no_inputs(self): required_writes = {"write.me"} output_diagnostics = action_tracer.diagnose_stale_outputs( accesses=[], access_constraints=action_tracer.AccessConstraints( required_writes=required_writes), ) self.assertEqual( output_diagnostics, action_tracer.StalenessDiagnostics( required_writes=required_writes, nonexistent_outputs={"write.me"}), )
def test_stale_output_no_inputs(self): required_writes = {"write.me"} with mock.patch.object(os.path, 'exists', return_value=True) as mock_exists: output_diagnostics = action_tracer.diagnose_stale_outputs( accesses=[], access_constraints=action_tracer.AccessConstraints( required_writes=required_writes), ) mock_exists.assert_called_once() self.assertEqual( output_diagnostics, action_tracer.StalenessDiagnostics(required_writes=required_writes), )
def test_missing_write_with_used_input(self): used_input = "read.me" required_writes = {"write.me"} output_diagnostics = action_tracer.diagnose_stale_outputs( accesses=[action_tracer.Read(used_input)], access_constraints=action_tracer.AccessConstraints( allowed_reads={used_input}, required_writes=required_writes, ), ) self.assertEqual( output_diagnostics, action_tracer.StalenessDiagnostics( required_writes=required_writes, nonexistent_outputs={"write.me"}), )
def test_stale_output_with_multiple_used_inputs(self): def fake_read_ctime(path: str): if path == "read.me": return 200 if path == "read.me.newer": return 300 raise Exception(f'fake_read_ctime for unexpected path: {path}') def fake_write_ctime(path: str): if path.startswith("write"): return 250 raise Exception(f'fake_write_ctime for unexpected path: {path}') used_input = "read.me" # Make sure the timestamp of the newest input is used for comparison. used_input_newer = "read.me.newer" required_writes = {"write.me"} with mock.patch.object(os.path, 'exists', return_value=True) as mock_exists: with mock.patch.object(os.path, 'getctime', wraps=fake_read_ctime) as mock_read_ctime: with mock.patch.object( action_tracer, 'realpath_ctime', wraps=fake_write_ctime) as mock_write_ctime: output_diagnostics = action_tracer.diagnose_stale_outputs( accesses=[ action_tracer.Read(used_input), action_tracer.Read(used_input_newer), ], access_constraints=action_tracer.AccessConstraints( allowed_reads={used_input, used_input_newer}, required_writes=required_writes), ) mock_exists.assert_called_once() mock_read_ctime.assert_called() mock_write_ctime.assert_called() self.assertEqual( output_diagnostics, action_tracer.StalenessDiagnostics( required_writes=required_writes, # newer input is used for comparison newest_input=used_input_newer, stale_outputs={"write.me"}), )