示例#1
0
    def test_timestamps(self):
        '''
        Ensure that modifying a timestamp on one of the inputs has no effect.
        '''
        root = self.mkdtemp()
        c = Cache(root)

        input = self.mkstemp()
        with open(input, 'wt') as f:
            f.write('foo bar')

        inputs = prime_inputs([input])

        cwd = os.getcwd()
        c.save(['arg1', 'arg2'], cwd, 'hello world', inputs)

        # Bump the timestamps on the input.
        st = os.stat(input)
        os.utime(input, (st[stat.ST_ATIME] + 3600, st[stat.ST_MTIME] + 3600))

        # Ensure we can find what we just saved.
        output = c.load(['arg1', 'arg2'], cwd)
        self.assertEqual(output, 'hello world')

        # And after a flush.
        c.flush()
        output = c.load(['arg1', 'arg2'], cwd)
        self.assertEqual(output, 'hello world')
示例#2
0
    def test_miss_on_disk2(self):
        '''
        Same as the in-memory miss test except we flush the cache in-between,
        at a point at which the entry is already invalid. The invalidity is not
        actually detected then, but the later lookup should still miss.
        '''
        root = self.mkdtemp()
        c = Cache(root)

        input = self.mkstemp()
        with open(input, 'wt') as f:
            f.write('foo bar')

        inputs = prime_inputs([input])

        cwd = os.getcwd()
        c.save(['arg1', 'arg2'], cwd, 'hello world', inputs)

        # Now cause the entry to be invalid by modifying inputs.
        with open(input, 'wt') as f:
            f.write('bar foo')

        # Flush the (now invalid) entry to disk.
        c.flush()

        # Ensure we miss when now performing a lookup.
        output = c.load(['arg1', 'arg2'], cwd)
        self.assertIsNone(output)
示例#3
0
    def test_cache_hit_truncate(self):
        '''
        A previous accelerator bug resulted in the output file not being
        truncated before the accelerator wrote to it. The result was that an
        output resulting from a cache hit that was delivered via the
        accelerator would have trailing garbage if it was shorter than the
        existing file content. More specifically, the following sequence could
        occur:

          1. Build with cache A enabled and "short string" is output and
             cached;
          2. Build with different config and "a slightly longer string" is
             output (and cached);
          3. Build with original config and the accelerator enabled and "short
             string" is retrieved, but written without truncating the output.

        As a result, the final file content would end up as "short stringonger
        string". This test validates that this problem has not been
        reintroduced.
        '''

        root = self.mkdtemp()

        internal_root = os.path.join(root, version(), 'cachea')
        c = Cache(internal_root)

        # Setup a basic, single-input entry.
        input1 = self.mkstemp()
        with open(input1, 'wt') as f:
            f.write('hello world')
        inputs = prime_inputs([input1])

        cwd = self.mkdtemp()

        output = self.mkstemp()

        args = ['--cache-dir', root, '--outfile', output]

        # Write the entry to the cache with a specific short value.
        content = 'moo cow'
        c.save(args[:-2], cwd, content, inputs)
        c.flush()

        del c

        # Now write something *longer* into the output file.
        with open(output, 'wt') as f:
            f.write('some lengthier text')

        # Now run the accelerator to retrieve the original, shorter output.
        ret, stdout, stderr = self.execute([self.accelerator] + args, cwd=cwd)

        # It should have hit the cache and written the correct, shorter output.
        self.assertEqual(ret, 0)
        self.assertEqual(stdout, '')
        self.assertEqual(stderr, '')
        with open(output) as f:
            data = f.read()
        self.assertEqual(data, content)
示例#4
0
    def test_basic_valgrind(self):
        root = self.mkdtemp()

        # CAmkES internally suffixes the root with a couple of things to
        # namespace the cache.
        internal_root = os.path.join(root, version(), 'cachea')
        c = Cache(internal_root)

        # Construct some fake inputs.
        input1 = self.mkstemp()
        with open(input1, 'wt') as f:
            f.write('hello world')
        input2 = self.mkstemp()
        with open(input2, 'wt') as f:
            f.write('foo bar')
        inputs = prime_inputs([input1, input2])

        # And a fake working directory.
        cwd = self.mkdtemp()

        # Imagine we were saving the output from the following file.
        output = self.mkstemp()

        # So the command line arguments would be:
        args = ['--cache-dir', root, '--outfile', output]

        # Save the entry. Note that we truncate the args because the runner and
        # the accelerator strip --outfile arguments before interacting with the
        # cache.
        c.save(args[:-2], cwd, 'moo cow', inputs)
        c.flush()

        # We're done with the native cache.
        del c

        # Now let's try to read back the cache entry from the accelerator.
        _, _, stderr = self.execute(VALGRIND + [self.debug_accelerator] + args,
                                    cwd=cwd)
        if valgrind_found_leak(stderr):
            self.fail('camkes-accelerator %s leaks memory:\n%s' %
                      (' '.join(args), stderr))

        _, _, stderr = self.execute(VALGRIND + [self.accelerator] + args,
                                    cwd=cwd)
        if valgrind_found_leak(stderr):
            self.fail('camkes-accelerator %s leaks memory (not reproducible '
                      'in debug mode):\n%s' % (' '.join(args), stderr))
示例#5
0
    def test_basic(self):
        '''
        Test we can save and retrieve something (expected case).
        '''
        root = self.mkdtemp()

        # CAmkES internally suffixes the root with a couple of things to
        # namespace the cache.
        internal_root = os.path.join(root, version(), 'cachea')
        c = Cache(internal_root)

        # Construct some fake inputs.
        input1 = self.mkstemp()
        with open(input1, 'wt') as f:
            f.write('hello world')
        input2 = self.mkstemp()
        with open(input2, 'wt') as f:
            f.write('foo bar')
        inputs = prime_inputs([input1, input2])

        # And a fake working directory.
        cwd = self.mkdtemp()

        # Imagine we were saving the output from the following file.
        output = self.mkstemp()

        # So the command line arguments would be:
        args = ['--cache-dir', root, '--outfile', output]

        # Save the entry. Note that we truncate the args because the runner and
        # the accelerator strip --outfile arguments before interacting with the
        # cache.
        c.save(args[:-2], cwd, 'moo cow', inputs)
        c.flush()

        # We're done with the native cache.
        del c

        # Now let's try to read back the cache entry from the accelerator.
        ret, _, _ = self.execute([self.accelerator] + args, cwd=cwd)
        self.assertEqual(ret, 0)

        # If it worked, we should have the output in the expected place.
        with open(output, 'rt') as f:
            data = f.read()
        self.assertEqual(data, 'moo cow')
示例#6
0
    def test_directory_creation(self):
        '''
        The cache should be capable of creating necessary subdirectories under
        its root.
        '''
        root = os.path.join(self.mkdtemp(), 'non-existent')

        c = Cache(root)

        input = self.mkstemp()
        with open(input, 'wt') as f:
            f.write('foo bar')

        inputs = prime_inputs([input])

        c.save(['arg1', 'arg2'], os.getcwd(), 'hello world', inputs)
        c.flush()
示例#7
0
    def test_no_inputs(self):
        '''
        Ensure we can handle an entry with no inputs.
        '''
        root = self.mkdtemp()
        c = Cache(root)

        inputs = prime_inputs([])

        cwd = os.getcwd()
        c.save(['arg1', 'arg2'], cwd, 'hello world', inputs)

        # Ensure we can find what we just saved.
        output = c.load(['arg1', 'arg2'], cwd)
        self.assertEqual(output, 'hello world')

        # Ensure it is preserved after a flush.
        c.flush()
        output = c.load(['arg1', 'arg2'], cwd)
        self.assertEqual(output, 'hello world')
示例#8
0
    def test_cache_miss_inputs_valgrind(self):
        # As for the basic test case...
        root = self.mkdtemp()

        internal_root = os.path.join(root, version(), 'cachea')
        c = Cache(internal_root)

        input1 = self.mkstemp()
        with open(input1, 'wt') as f:
            f.write('hello world')
        input2 = self.mkstemp()
        with open(input2, 'wt') as f:
            f.write('foo bar')
        inputs = prime_inputs([input1, input2])

        cwd = self.mkdtemp()

        output = self.mkstemp()

        args = ['--cache-dir', root, '--outfile', output]

        c.save(args[:-2], cwd, 'moo cow', inputs)
        c.flush()

        del c

        # Now let's modify one of the inputs.
        with open(input2, 'at') as f:
            f.write('foo bar')

        _, _, stderr = self.execute(VALGRIND + [self.debug_accelerator] + args,
                                    cwd=cwd)
        if valgrind_found_leak(stderr):
            self.fail('camkes-accelerator %s leaks memory:\n%s' %
                      (' '.join(args), stderr))

        _, _, stderr = self.execute(VALGRIND + [self.accelerator] + args,
                                    cwd=cwd)
        if valgrind_found_leak(stderr):
            self.fail('camkes-accelerator %s leaks memory (not reproducible '
                      'in debug mode):\n%s' % (' '.join(args), stderr))
示例#9
0
    def test_no_args(self):
        root = self.mkdtemp()
        c = Cache(root)

        input = self.mkstemp()
        with open(input, 'wt') as f:
            f.write('foo bar')

        inputs = prime_inputs([input])

        cwd = os.getcwd()
        c.save([], cwd, 'hello world', inputs)

        # Ensure we can find what we just saved.
        output = c.load([], cwd)
        self.assertEqual(output, 'hello world')

        # Ensure it is preserved after a flush.
        c.flush()
        output = c.load([], cwd)
        self.assertEqual(output, 'hello world')
示例#10
0
    def test_cache_miss_inputs(self):
        '''
        Test that we correctly miss when one of the inputs has changed.
        '''
        # As for the basic test case...
        root = self.mkdtemp()

        internal_root = os.path.join(root, version(), 'cachea')
        c = Cache(internal_root)

        input1 = self.mkstemp()
        with open(input1, 'wt') as f:
            f.write('hello world')
        input2 = self.mkstemp()
        with open(input2, 'wt') as f:
            f.write('foo bar')
        inputs = prime_inputs([input1, input2])

        cwd = self.mkdtemp()

        output = self.mkstemp()

        args = ['--cache-dir', root, '--outfile', output]

        c.save(args[:-2], cwd, 'moo cow', inputs)
        c.flush()

        del c

        # Now let's modify one of the inputs.
        with open(input2, 'at') as f:
            f.write('foo bar')

        ret, stdout, stderr = self.execute([self.accelerator] + args, cwd=cwd)

        # It should have missed (== non-zero return value with no output).
        self.assertNotEqual(ret, 0)
        self.assertEqual(stdout, '')
        self.assertEqual(stderr, '')
示例#11
0
    def test_basic_with_flush(self):
        '''
        Same as the basic test, but we'll flush in-between to ensure we perform
        an on-disk lookup.
        '''
        root = self.mkdtemp()
        c = Cache(root)

        input = self.mkstemp()
        with open(input, 'wt') as f:
            f.write('foo bar')

        inputs = prime_inputs([input])

        cwd = os.getcwd()
        c.save(['arg1', 'arg2'], cwd, 'hello world', inputs)
        c.flush()

        # Ensure we can find what we just saved.
        output = c.load(['arg1', 'arg2'], cwd)

        self.assertEqual(output, 'hello world')
示例#12
0
    def test_miss_from_missing_file2(self):
        '''
        As above, but flush the entry to disk first.
        '''
        root = self.mkdtemp()
        c = Cache(root)

        _, input = tempfile.mkstemp()
        with open(input, 'wt') as f:
            f.write('foo bar')

        inputs = prime_inputs([input])

        cwd = os.getcwd()
        c.save(['arg1', 'arg2'], cwd, 'hello world', inputs)
        c.flush()

        # Now cause the entry to be invalid by deleting its input.
        os.remove(input)

        # Ensure we miss when now performing a lookup.
        output = c.load(['arg1', 'arg2'], cwd)
        self.assertIsNone(output)
示例#13
0
    def test_miss_on_disk1(self):
        '''
        Same as the in-memory miss test except we flush the cache in-between.
        '''
        root = self.mkdtemp()
        c = Cache(root)

        input = self.mkstemp()
        with open(input, 'wt') as f:
            f.write('foo bar')

        inputs = prime_inputs([input])

        cwd = os.getcwd()
        c.save(['arg1', 'arg2'], cwd, 'hello world', inputs)
        c.flush()

        # Now cause the entry to be invalid by modifying inputs.
        with open(input, 'wt') as f:
            f.write('bar foo')

        # Ensure we miss when now performing a lookup.
        output = c.load(['arg1', 'arg2'], cwd)
        self.assertIsNone(output)