async def test_write_blocks_read(self): lock = TreeLock() # Same path acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[], write=[path('/a/b/c')]), lock(read=[path('/a/b/c')], write=[]), ), complete(0), complete(1)) self.assertEqual(acquired_history[0], [True, False]) self.assertEqual(acquired_history[1], [True, True]) # Descendant path acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[], write=[path('/a/b/c')]), lock(read=[path('/a/b/c/d/e')], write=[]), ), complete(0), complete(1)) self.assertEqual(acquired_history[0], [True, False]) self.assertEqual(acquired_history[1], [True, True]) # Ancestor path (ensures the order doesn't matter) acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[], write=[path('/a/b/c')]), lock(read=[path('/a')], write=[]), ), complete(0), complete(1)) self.assertEqual(acquired_history[0], [True, False]) self.assertEqual(acquired_history[1], [True, True])
async def test_writes_to_same_lineage(self): lock = TreeLock() # Same path acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[], write=[path('/a/b/c'), path('/a/b/c')]), ), complete(0)) self.assertEqual(acquired_history[0], [True]) # Descendant path acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[], write=[path('/a/b/c'), path('/a/b/c/d/e')]), ), complete(0)) self.assertEqual(acquired_history[0], [True]) # Ancestor path (ensures the order doesn't matter) acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[], write=[path('/a/b/c'), path('/a')]), ), complete(0)) self.assertEqual(acquired_history[0], [True]) # Descendant and ancestor paths not in order, highest first acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[], write=[path('/a/b'), path('/a/b/c/d/e/f'), path('/a/b/c'), path('/a/b/c/d/e')]), ), complete(0)) self.assertEqual(acquired_history[0], [True]) # Descendant and ancestor paths not in order, deepest first acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[], write=[path('/a/b/c/d/e/f'), path('/a/b'), path('/a/b/c/d/e'), path('/a/b/c')]), ), complete(0)) self.assertEqual(acquired_history[0], [True])
async def test_read_allows_unrelated_read(self): lock = TreeLock() acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[path('/a/b/c')], write=[]), lock(read=[path('/a/b/e')], write=[]), ), complete(0), complete(1)) self.assertEqual(acquired_history[0], [True, True])
async def test_cancellation_after_acquisition_unblocks_read(self): lock = TreeLock() acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[], write=[path('/a/b/c')]), lock(read=[path('/a/b/c/d')], write=[]), ), cancel(0), complete(1)) self.assertEqual(acquired_history[0], [True, False]) self.assertEqual(acquired_history[1], [True, True])
async def test_blocked_read_root_and_write_block_write(self): lock = TreeLock() acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[path('/')], write=[path('/a/b/c')]), lock(read=[], write=[path('/a/b/d')]), ), complete(0), complete(1)) self.assertEqual(acquired_history[0], [True, False]) self.assertEqual(acquired_history[1], [True, True])
async def test_exception_after_acquisition_unblocks_write(self): lock = TreeLock() tasks = create_tree_tasks( lock(read=[], write=[path('/a/b/c')]), lock(read=[], write=[path('/a/b/c/d')]), ) exp = Exception('Raised exception') acquired_history = await mutate_tasks_in_sequence( tasks, exception(0, exp), complete(1)) self.assertEqual(tasks[0].task.exception(), exp) self.assertEqual(acquired_history[0], [True, False]) self.assertEqual(acquired_history[1], [True, True])
async def test_lock_modes_can_be_reused(self): lock = TreeLock() lock_write_1 = lock(read=[], write=[path('/a/b/c')]) lock_write_2 = lock(read=[], write=[path('/a/b/c')]) acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock_write_1, lock_write_2), complete(0), complete(1)) self.assertEqual(acquired_history[0], [True, False]) self.assertEqual(acquired_history[1], [True, True]) acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock_write_1, lock_write_2), complete(0), complete(1)) self.assertEqual(acquired_history[0], [True, False]) self.assertEqual(acquired_history[1], [True, True])
async def test_reads_and_write_to_same_lineage(self): lock = TreeLock() # Same path acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[path('/a/b/c')], write=[path('/a/b/c')]), ), complete(0)) self.assertEqual(acquired_history[0], [True]) # Write descendant path of read acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[path('/a/b/c')], write=[path('/a/b/c/d/e')]), ), complete(0)) self.assertEqual(acquired_history[0], [True]) # Write ancestor path of read acquired_history = await mutate_tasks_in_sequence(create_tree_tasks( lock(read=[path('/a/b/c')], write=[path('/a')]), ), complete(0)) self.assertEqual(acquired_history[0], [True])