def test_01_watch(self): """Test creating a watch on a node.""" nodeCache = NodeCache() with nodeCache.watch('/a/b/c') as w: self.assertTrue(w in nodeCache.watchedNodes) self.assertFalse(w.dirty) with nodeCache.watch('/a/b/c') as w2: self.assertFalse(w2.dirty) self.assertTrue(w in nodeCache.watchedNodes) self.assertTrue(w2 in nodeCache.watchedNodes) self.assertTrue(w in nodeCache.watchedNodes) self.assertFalse(w2 in nodeCache.watchedNodes) self.assertFalse(w in nodeCache.watchedNodes) self.assertFalse(w2 in nodeCache.watchedNodes) self.assertEqual(len(nodeCache.watchedNodes), 0) with self.assertRaises(IOError): with nodeCache.watch('/a/b/c') as w: self.assertTrue(w in nodeCache.watchedNodes) raise IOError('atest') self.assertTrue(False) self.assertFalse(w in nodeCache.watchedNodes) self.assertEqual(len(nodeCache.watchedNodes), 0) with nodeCache.watch('/a/b/c') as w: w.insert('d') self.assertEqual( nodeCache['/a/b/c'], 'd') self.assertEqual(len(nodeCache.watchedNodes), 0)
def test_01_watch(self): """Test creating a watch on a node.""" nodeCache = NodeCache() with nodeCache.watch('/a/b/c') as w: self.assertTrue(w in nodeCache.watchedNodes) self.assertFalse(w.dirty) with nodeCache.watch('/a/b/c') as w2: self.assertFalse(w2.dirty) self.assertTrue(w in nodeCache.watchedNodes) self.assertTrue(w2 in nodeCache.watchedNodes) self.assertTrue(w in nodeCache.watchedNodes) self.assertFalse(w2 in nodeCache.watchedNodes) self.assertFalse(w in nodeCache.watchedNodes) self.assertFalse(w2 in nodeCache.watchedNodes) self.assertEqual(len(nodeCache.watchedNodes), 0) with self.assertRaises(IOError): with nodeCache.watch('/a/b/c') as w: self.assertTrue(w in nodeCache.watchedNodes) raise IOError('atest') self.assertTrue(False) self.assertFalse(w in nodeCache.watchedNodes) self.assertEqual(len(nodeCache.watchedNodes), 0) with nodeCache.watch('/a/b/c') as w: w.insert('d') self.assertEqual(nodeCache['/a/b/c'], 'd') self.assertEqual(len(nodeCache.watchedNodes), 0)
def test_01_volatile(self): """ test marking part of the tree as volatile""" nodeCache = NodeCache() nodeCache['/a/b'] = 'a' nodeCache['/a/b/c'] = 'b' nodeCache['/a/b/c/'] = 'c' nodeCache['/a/b/c/d'] = 'd' self.assertTrue('/a/b' in nodeCache) self.assertTrue('/a/b/c' in nodeCache) self.assertTrue('/a/b/c/' in nodeCache) self.assertTrue('/a/b/c/d' in nodeCache) with nodeCache.volatile('/a/b/c/') as v: self.assertTrue('/a/b' in nodeCache) self.assertFalse('/a/b/c' in nodeCache) self.assertFalse('/a/b/c/' in nodeCache) self.assertFalse('/a/b/c/d' in nodeCache) self.assertTrue(v in nodeCache.volatileNodes) # Nested with the same path with nodeCache.volatile('/a/b/c') as v2: self.assertTrue(v in nodeCache.volatileNodes) self.assertTrue(v2 in nodeCache.volatileNodes) self.assertTrue(v in nodeCache.volatileNodes) self.assertFalse(v2 in nodeCache.volatileNodes) self.assertFalse(v in nodeCache.volatileNodes) self.assertEqual(len(nodeCache.volatileNodes), 0) with self.assertRaises(IOError): with nodeCache.volatile('/a/b/c') as v: self.assertTrue(v in nodeCache.volatileNodes) raise IOError('atest') self.assertTrue(False) self.assertFalse(v in nodeCache.volatileNodes) self.assertEqual(len(nodeCache.volatileNodes), 0)
def test_00_constructor(self): """Test basic operation of the NodeCache as a dict.""" nodeCache = NodeCache() self.assertEqual(len(nodeCache.watchedNodes), 0) self.assertEqual(len(nodeCache.volatileNodes), 0) nodeCache['a'] = 'b' nodeCache['b'] = 'c' self.assertEqual(nodeCache['a'], 'b') self.assertEqual(len(nodeCache), 2) self.assertTrue('a' in nodeCache) del nodeCache['a'] self.assertFalse('a' in nodeCache) self.assertEqual(len(nodeCache), 1) self.assertEqual(nodeCache['a'], None)
def test_02_watchnvolatile(self): """test watch and volitile working together.""" nodeCache = NodeCache() with nodeCache.watch('/a/b/c/') as w: w.insert('d') self.assertEqual(nodeCache['/a/b/c'], 'd') # Make a sub-tree volatile. This should not effect the watched # directory. with nodeCache.volatile('/a/b/c/d'): self.assertEqual(nodeCache['/a/b/c'], 'd') self.assertTrue('/a/b/c' in nodeCache) with nodeCache.volatile('/a/b/c'): self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertFalse('/a/b/c' in nodeCache) # Set up a watch and then make a parent node volatile. Caching should be # disabled on the watched tree. with nodeCache.watch('/a/b/c') as w: self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertTrue('/a/b/c' in nodeCache) with nodeCache.volatile('/a/b/'): pass self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertFalse('/a/b/c' in nodeCache) # Watches are gone, it should now be possible to cache nodes again. with nodeCache.watch('/a/b/c') as w: self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertTrue('/a/b/c' in nodeCache) # Set up a volatile block first and ensure the cache is disabled. with nodeCache.volatile('/a/b/c'): self.assertFalse('/a/b/c' in nodeCache) with nodeCache.watch('/a/b/c') as w: w.insert('d') self.assertFalse('/a/b/c' in nodeCache) with nodeCache.watch('/a/b/c/d') as w: w.insert('d') self.assertFalse('/a/b/c/d' in nodeCache) with nodeCache.watch('/a/e/f/g') as w: w.insert('d') self.assertTrue('/a/e/f/g' in nodeCache)
def test_truncate(self): callCount = [0] def mock_read(block_size): callCount[0] += 1 if callCount[0] == 1: return "1234" else: return None file = "/dir1/dir2/file" testfs = vofs.VOFS(self.testMountPoint, self.testCacheDir, opt) node = Mock(spec=vos.Node) node.isdir = Mock(return_value=False) node.props = Object node.props.get = Mock(side_effect=SideEffect( { ('islocked', False): False, ('length', ): 10, ('MD5', ): 12354, }, name="node.props.get")) node.type = "vos:DataNode" node.uri = "vos:/dir1/dir2/file" testfs.client = Object() testfs.client.getNode = Mock(return_value=node) testfs.client.close = Mock() testfs.client.read = Mock(side_effect=mock_read) testfs.client.copy = Mock() vos_VOFILE = Object() vos_VOFILE.close = Mock() vos_VOFILE.read = Mock(side_effect=mock_read) testfs.client.open = Mock(return_value=vos_VOFILE) testfs.client.nodeCache = Object() testfs.client.nodeCache = NodeCache() # Truncate a non-open file to 0 bytes testfs.cache.open = Mock(wraps=testfs.cache.open) origRelease = FileHandle.release origTruncate = FileHandle.truncate with nested(patch('vos.CadcCache.FileHandle.release'), patch('vos.CadcCache.FileHandle')) as (mockRelease, mockFileHandle): mockFileHandle.return_value = MyFileHandle(file, testfs.cache, None) mockFileHandle.return_value.readData = \ Mock(wraps=mockFileHandle.return_value.readData) mockRelease.wraps = origRelease # TODO This doesn't really work, # release is not called and so open # files are being leaked testfs.truncate(file, 0) self.assertEqual(testfs.cache.open.call_count, 1) self.assertEqual(testfs.cache.open.call_args[0][0], file) self.assertFalse(testfs.cache.open.call_args[0][1]) self.assertTrue(testfs.cache.open.call_args[0][2]) mockRelease.assert_called_once_with() self.assertEqual(mockFileHandle.return_value.readData.call_count, 1) # Truncate a non-open file past the start of the file. testfs.cache.open.reset_mock() with nested(patch('vos.CadcCache.FileHandle.release'), patch('vos.CadcCache.FileHandle.readData')) as mocks: mockRelease = mocks[0] mockReadData = mocks[1] mockRelease.wraps = origRelease # TODO This doesn't really work, # release is not called and so open # files are being leaked with patch('vos.CadcCache.FileHandle.truncate') as mockTruncate: mockTruncate.wraps = origTruncate # TODO Same issue as the # mockRelease TODO above. testfs.truncate(file, 5) self.assertEqual(testfs.cache.open.call_args[0][0], file) self.assertFalse(testfs.cache.open.call_args[0][1]) mockTruncate.assert_called_once_with(5) mockRelease.assert_called_once_with() # Truncate with an exception returned by the CadcCache truncate testfs.cache.open.reset_mock() with nested(patch('vos.CadcCache.FileHandle.release'), patch('vos.CadcCache.FileHandle.readData')) as mocks: mockRelease = mocks[0] mockReadData = mocks[1] mockRelease.wraps = origRelease # TODO This doesn't really work, # release is not called and so open # files are being leaked with patch('vos.CadcCache.FileHandle.truncate') as mockTruncate: mockTruncate.side_effect = NotImplementedError("an error") with self.assertRaises(NotImplementedError): testfs.truncate(file, 5) self.assertEqual(testfs.cache.open.call_args[0][0], file) self.assertFalse(testfs.cache.open.call_args[0][1]) mockRelease.assert_called_once_with() # Truncate an already opened file given the file handle. with nested(patch('vos.CadcCache.FileHandle.release'), patch('vos.CadcCache.FileHandle.readData')) as mocks: mockRelease = mocks[0] mockReadData = mocks[1] mockRelease.wraps = origRelease # TODO This doesn't really work, # release is not called and so open # files are being leaked try: fh = testfs.open(file, os.O_RDWR | os.O_CREAT, None) testfs.cache.open.reset_mock() with patch( 'vos.CadcCache.FileHandle.truncate') as mockTruncate: mockTruncate.wraps = origTruncate # TODO Same issue as the # mockRelease TODO above. testfs.truncate(file, 20, fh) # Open and release should not be called, truncate should be # called. self.assertEqual(testfs.cache.open.call_count, 0) mockTruncate.assert_called_once_with(20) self.assertEqual(mockRelease.call_count, 0) finally: testfs.release(file, fh) # Create a new file system for testing. This is required because of the # leaked file handles from the previous tests. testfs2 = vofs.VOFS(self.testMountPoint, self.testCacheDir, opt) testfs2.client = testfs.client testfs = None testfs2.cache.open = Mock(wraps=testfs2.cache.open) # Truncate a read only file handle. with nested(patch('vos.CadcCache.FileHandle.release'), patch('vos.CadcCache.FileHandle')) as \ (mockRelease, mockFileHandle): mockRelease.wraps = origRelease mockFileHandle.return_value = MyFileHandle(file, testfs2.cache, None) mockFileHandle.return_value.readData = \ Mock(wraps=mockFileHandle.return_value.readData) try: fh = testfs2.open(file, os.O_RDONLY, None) testfs2.cache.open.reset_mock() with patch( 'vos.CadcCache.FileHandle.truncate') as mockTruncate: mockTruncate.wraps = origTruncate with self.assertRaises(FuseOSError): testfs2.truncate(file, 20, fh) # Open, release and truncate should not be called. self.assertEqual(testfs2.cache.open.call_count, 0) self.assertEqual(mockTruncate.call_count, 0) self.assertEqual(mockRelease.call_count, 0) finally: testfs2.release(file, fh) # Truncate with an invalid file descriptor. with self.assertRaises(FuseOSError) as e: testfs2.truncate(file, 20, -1) self.assertEqual(e.exception.errno, EIO)
def test_02_watchnvolatile(self): """test watch and volitile working together.""" nodeCache = NodeCache() with nodeCache.watch('/a/b/c/') as w: w.insert('d') self.assertEqual( nodeCache['/a/b/c'], 'd') # Make a sub-tree volatile. This should not effect the watched # directory. with nodeCache.volatile('/a/b/c/d'): self.assertEqual( nodeCache['/a/b/c'], 'd') self.assertTrue('/a/b/c' in nodeCache) with nodeCache.volatile('/a/b/c'): self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertFalse('/a/b/c' in nodeCache) # Set up a watch and then make a parent node volatile. Caching should be # disabled on the watched tree. with nodeCache.watch('/a/b/c') as w: self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertTrue('/a/b/c' in nodeCache) with nodeCache.volatile('/a/b/'): pass self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertFalse('/a/b/c' in nodeCache) # Watches are gone, it should now be possible to cache nodes again. with nodeCache.watch('/a/b/c') as w: self.assertFalse('/a/b/c' in nodeCache) w.insert('d') self.assertTrue('/a/b/c' in nodeCache) # Set up a volatile block first and ensure the cache is disabled. with nodeCache.volatile('/a/b/c'): self.assertFalse('/a/b/c' in nodeCache) with nodeCache.watch('/a/b/c') as w: w.insert('d') self.assertFalse('/a/b/c' in nodeCache) with nodeCache.watch('/a/b/c/d') as w: w.insert('d') self.assertFalse('/a/b/c/d' in nodeCache) with nodeCache.watch('/a/e/f/g') as w: w.insert('d') self.assertTrue('/a/e/f/g' in nodeCache)