def create_component(name: str, description: str, owner: str, tags: typing.List[str] = []): """Creates a component entity in the database.""" store = Store(_db_uri) store.create_component(name, description, owner, tags)
class TestDags(unittest.TestCase): def setUp(self): self.store = Store("test") def testLinkedList(self): # Create chain of component runs expected_result = [] num_runs = 10 for i in range(1, num_runs + 1): self.store.create_component(f"mock_component_{i}", "", "") inp = self.store.get_io_pointer(f"iop_{i}") out = self.store.get_io_pointer(f"iop_{i + 1}") cr = self.store.initialize_empty_component_run( f"mock_component_{i}") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(inp) cr.add_output(out) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) expected_result.append((num_runs - i, i)) # Reverse the expected result expected_result.reverse() # Trace the final output trace = self.store.trace("iop_11") level_id = [(level, cr.id) for level, cr in trace] self.assertEqual(expected_result, level_id) def testVersionedComputation(self): # Run the same computation many times self.store.create_component("mock_component", "", "") num_runs = 10 for i in range(1, num_runs + 1): inp = self.store.get_io_pointer("inp") out = self.store.get_io_pointer("out") cr = self.store.initialize_empty_component_run("mock_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(inp) cr.add_output(out) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Trace the out pointer. Only most recent run ID should show. trace = self.store.trace("out") self.assertEqual(len(trace), 1) self.assertEqual(trace[0][0], 0) self.assertEqual(trace[0][1].id, num_runs) def testTree(self): # Create a tree of component runs, 5 levels deep num_levels = 2 global cr_counter global iop_counter cr_counter = 1 iop_counter = 1 def create_tree(level, inp): if level == num_levels: return global cr_counter global iop_counter self.store.create_component(f"mock_component_{cr_counter}", "", "") cr = self.store.initialize_empty_component_run( f"mock_component_{cr_counter}") cr_counter += 1 cr.set_start_timestamp() cr.set_end_timestamp() # Create output pointers out1 = self.store.get_io_pointer(f"iop_{iop_counter}") iop_counter += 1 out2 = self.store.get_io_pointer(f"iop_{iop_counter}") iop_counter += 1 # Add and commit component run cr.add_input(inp) cr.add_outputs([out1, out2]) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Create left and right trees create_tree(level + 1, out1) create_tree(level + 1, out2) # Create first input pointer and tree of computation inp = self.store.get_io_pointer(f"iop_{iop_counter}") iop_counter += 1 create_tree(0, inp) # Grab last iop id and trace it last_iop_id = f"iop_{iop_counter - 1}" trace = self.store.trace(last_iop_id) level_id = [(level, cr.id) for level, cr in trace] self.assertEqual(level_id, [(0, 3), (1, 1)]) def testCycle(self): # Create cycle. Since dependencies are versioned, we shouldn't run # into problems. # Create io pointers and components iop1 = self.store.get_io_pointer("iop1") iop2 = self.store.get_io_pointer("iop2") self.store.create_component("component_1", "", "") self.store.create_component("component_2", "", "") # Create component runs cr = self.store.initialize_empty_component_run("component_1") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(iop1) cr.add_output(iop2) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) cr = self.store.initialize_empty_component_run("component_2") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(iop2) cr.add_output(iop1) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Trace iop1 trace_1 = [(level, cr.id) for level, cr in self.store.trace("iop1")] trace_2 = [(level, cr.id) for level, cr in self.store.trace("iop2")] self.assertEqual(trace_1, [(0, 2), (1, 1)]) self.assertEqual(trace_2, [(0, 1)]) def testStaleUpdate(self): # Create computation with stale update. iop1 = self.store.get_io_pointer("iop1") iop2 = self.store.get_io_pointer("iop2") iop3 = self.store.get_io_pointer("iop3") iop4 = self.store.get_io_pointer("iop4") self.store.create_component("component_1", "", "") self.store.create_component("component_2", "", "") # Create first component cr = self.store.initialize_empty_component_run("component_1") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(iop1) cr.add_output(iop2) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Create second component run cr = self.store.initialize_empty_component_run("component_1") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(iop1) cr.add_output(iop3) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Create third component run that depends on the first (stale update) cr = self.store.initialize_empty_component_run("component_2") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(iop2) cr.add_output(iop4) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Trace iop4 trace = [(level, cr.id, cr.stale) for level, cr in self.store.trace("iop4")] res = [ ( 0, 3, [ "component_1 (ID 1) has 1 fresher run that began " + "before this component run started." ], ), (1, 1, []), ] self.assertEqual(trace, res) def testStaleTime(self): # Create computation with stale update. iop1 = self.store.get_io_pointer("iop1") iop2 = self.store.get_io_pointer("iop2") iop3 = self.store.get_io_pointer("iop3") self.store.create_component("component_1", "", "") self.store.create_component("component_2", "", "") now = datetime.utcnow() # Create first component cr = self.store.initialize_empty_component_run("component_1") start_month = now.month - 2 if now.month > 2 else (12 + now.month) - 2 start_year = now.year if now.month > 2 else now.year - 1 start_date = now.replace(month=start_month, year=start_year) cr.set_start_timestamp(start_date) cr.set_end_timestamp() cr.add_input(iop1) cr.add_output(iop2) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Create second component run cr = self.store.initialize_empty_component_run("component_2") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(iop2) cr.add_output(iop3) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Trace trace = [(level, cr.id, cr.stale) for level, cr in self.store.trace("iop3")] res = [ ( 0, 2, [ "component_1 (ID 1) was run " + f"{(now - start_date).days} days" + " ago." ], ), (1, 1, []), ] self.assertEqual(trace, res)
class TestStore(unittest.TestCase): def setUp(self): self.store = Store("test") def testComponent(self): self.store.create_component("test_component", "test_description", "shreya") component = self.store.get_component("test_component") self.assertEqual(component.name, "test_component") # Retrieve components with owner components = self.store.get_components(owner="shreya") self.assertEqual(1, len(components)) def testCompleteComponentRun(self): # Create component self.store.create_component("test_component", "test_description", "shreya") # Create component run cr = self.store.initialize_empty_component_run("test_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(IOPointer("inp")) cr.add_output(IOPointer("out")) self.store.commit_component_run(cr) # Test retrieval component_runs = self.store.get_history("test_component", limit=None) self.assertEqual(1, len(component_runs)) self.assertEqual(component_runs[0], cr) def testLogComponentRunWithoutComponentCreated(self): # Create a ComponentRun cr = self.store.initialize_empty_component_run("test_component_new") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(IOPointer("inp")) cr.add_output(IOPointer("out")) self.store.commit_component_run(cr) # Test retrieval component_runs = self.store.get_history("test_component_new", limit=None) self.assertEqual(1, len(component_runs)) self.assertEqual(component_runs[0], cr) def testIncompleteComponentRun(self): # Create component self.store.create_component("test_component", "test_description", "shreya") # Create incomplete component run cr = self.store.initialize_empty_component_run("test_component") with self.assertRaises(RuntimeError): self.store.commit_component_run(cr) def testTags(self): # Create component without tags self.store.create_component("test_component", "test_description", "shreya") # Add tags self.store.add_tags_to_component("test_component", ["tag1", "tag2"]) # Test retrieval component = self.store.get_component("test_component") tags = [t.name for t in component.tags] self.assertEqual(component.name, "test_component") self.assertEqual(set(tags), set(["tag1", "tag2"])) def testDuplicateTags(self): # Create component without tags self.store.create_component("test_component", "test_description", "shreya") # Add duplicate tags self.store.add_tags_to_component("test_component", ["tag1", "tag1"]) # Test retrieval component = self.store.get_component("test_component") tags = [t.name for t in component.tags] self.assertEqual(component.name, "test_component") self.assertEqual(tags, ["tag1"]) def testIOPointer(self): # Test there is no IOPointer with self.assertRaises(RuntimeError): self.store.get_io_pointer("iop", create=False) # Create IOPointer iop = self.store.get_io_pointer("iop") iop2 = self.store.get_io_pointer("iop") self.assertEqual(iop, iop2) def testIOPointers(self): # Create new IOPointers from scratch iop_names = [f"iop_{i}" for i in range(100)] iops = self.store.get_io_pointers(iop_names) iops2 = self.store.get_io_pointers(iop_names) self.assertEqual(set(iops), set(iops2)) def testKVIOPointer(self): iop_name = "name" iop_value = "value" iop = self.store.get_io_pointer(iop_name, iop_value) iop2 = self.store.get_io_pointer(iop_name, iop_value) self.assertEqual(iop, iop2) def testSetDependenciesFromInputs(self): # Create IO pointers inp = self.store.get_io_pointer("inp") out = self.store.get_io_pointer("out") another_out = self.store.get_io_pointer("another_out") # Create two component runs that have the same output self.store.create_component("test_component", "test_description", "shreya") for idx in range(2): cr = self.store.initialize_empty_component_run("test_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(inp) cr.add_output(out) self.store.commit_component_run(cr) # Create another two component runs that have the same output self.store.create_component("test_component", "test_description", "shreya") for idx in range(2): cr = self.store.initialize_empty_component_run("test_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(inp) cr.add_output(another_out) self.store.commit_component_run(cr) # Create new component run that depends on "out" pointer cr = self.store.initialize_empty_component_run("test_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_inputs([out, another_out]) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Retrieve latest component run and check dependencies component_runs = self.store.get_history("test_component", limit=None) self.assertTrue(component_runs[1] in component_runs[0].dependencies) self.assertTrue(component_runs[3] in component_runs[0].dependencies) def _set_up_computation(self): # Create dag of computation # Create component and IOPointers for i in range(1, 5): self.store.create_component(f"test_component_{i}", "test_description", "shreya") iop = [self.store.get_io_pointer(f"iop_{i}") for i in range(1, 5)] # Create component runs cr1 = self.store.initialize_empty_component_run("test_component_1") cr1.set_start_timestamp() cr1.set_end_timestamp() cr1.add_output(iop[0]) self.store.set_dependencies_from_inputs(cr1) self.store.commit_component_run(cr1) cr2 = self.store.initialize_empty_component_run("test_component_2") cr2.set_start_timestamp() cr2.set_end_timestamp() cr2.add_output(iop[0]) self.store.set_dependencies_from_inputs(cr2) self.store.commit_component_run(cr2) cr3 = self.store.initialize_empty_component_run("test_component_3") cr3.set_start_timestamp() cr3.set_end_timestamp() cr3.add_input(iop[0]) cr3.add_outputs([iop[1], iop[2]]) self.store.set_dependencies_from_inputs(cr3) self.store.commit_component_run(cr3) cr4 = self.store.initialize_empty_component_run("test_component_4") cr4.set_start_timestamp() cr4.set_end_timestamp() cr4.add_input(iop[2]) cr4.add_output(iop[3]) self.store.set_dependencies_from_inputs(cr4) self.store.commit_component_run(cr4) def testTrace(self): self._set_up_computation() # Call trace functionality trace = self.store.trace("iop_4") level_id = [(level, cr.id) for level, cr in trace] self.assertEqual(level_id, [(0, 4), (1, 3), (2, 2)]) def testEmptyTrace(self): with self.assertRaises(RuntimeError): self.store.trace("some_weird_pointer") with self.assertRaises(RuntimeError): self.store.web_trace("some_weird_pointer") def testWebTrace(self): self._set_up_computation() # Call web trace functionality. The ordering is nondeterministic. expected_res = [{ "id": "componentrun_4", "label": "test_component_4", "hasCaret": True, "isExpanded": True, "stale": [], "childNodes": [ { "id": "iopointer_iop_4", "label": "iop_4", "hasCaret": False, "parent": "componentrun_4", }, { "id": "componentrun_3", "label": "test_component_3", "hasCaret": True, "isExpanded": True, "stale": [], "childNodes": [ { "id": "iopointer_iop_2", "label": "iop_2", "hasCaret": False, "parent": "componentrun_3", }, { "id": "iopointer_iop_3", "label": "iop_3", "hasCaret": False, "parent": "componentrun_3", }, { "id": "componentrun_2", "label": "test_component_2", "hasCaret": True, "isExpanded": True, "stale": [], "childNodes": [{ "id": "iopointer_iop_1", "label": "iop_1", "hasCaret": False, "parent": "componentrun_2", }], }, ], }, ], }] web_trace = self.store.web_trace("iop_4") self.assertEqual(web_trace, expected_res) def testBasicFlaggedOutputs(self): # Create components and iopointers self.store.create_component("test_component_A", "test_description", "shreya") self.store.create_component("test_component_B", "test_description", "shreya") iop = [self.store.get_io_pointer(f"iop_{i}") for i in range(1, 5)] # Create component runs # First pipeline cr_A1 = self.store.initialize_empty_component_run("test_component_A") cr_A1.set_start_timestamp() cr_A1.set_end_timestamp() cr_A1.add_outputs([iop[0], iop[1]]) self.store.set_dependencies_from_inputs(cr_A1) self.store.commit_component_run(cr_A1) cr_B1 = self.store.initialize_empty_component_run("test_component_B") cr_B1.set_start_timestamp() cr_B1.set_end_timestamp() cr_B1.add_input(iop[0]) cr_B1.add_output(iop[2]) self.store.set_dependencies_from_inputs(cr_B1) self.store.commit_component_run(cr_B1) # Second pipeline, which builds off iop2 cr_B2 = self.store.initialize_empty_component_run("test_component_B") cr_B2.set_start_timestamp() cr_B2.set_end_timestamp() cr_B2.add_input(iop[1]) cr_B2.add_output(iop[3]) self.store.set_dependencies_from_inputs(cr_B2) self.store.commit_component_run(cr_B2) # Flag iop_3 and iop_4 self.store.set_io_pointer_flag("iop_3", True) self.store.set_io_pointer_flag("iop_4", True) # Run diagnose. It should output # [component_A, component_B, component_B]'s corresponding run IDs _, res = self.store.review_flagged_outputs() res = [(cr.id, count) for cr, count in res] expected_res = [(1, 2), (3, 1), (2, 1)] self.assertEqual(res, expected_res) def testManyFlaggedOutputs(self): # Create components and iopointers self.store.create_component("test_component_A", "test_description", "shreya") self.store.create_component("test_component_B", "test_description", "shreya") self.store.create_component("test_component_C", "test_description", "shreya") iop = [self.store.get_io_pointer(f"iop_{i}") for i in range(1, 8)] # Create component runs # First pipeline cr_A1 = self.store.initialize_empty_component_run("test_component_A") cr_A1.set_start_timestamp() cr_A1.set_end_timestamp() cr_A1.add_outputs([iop[0], iop[1]]) self.store.set_dependencies_from_inputs(cr_A1) self.store.commit_component_run(cr_A1) cr_B1 = self.store.initialize_empty_component_run("test_component_B") cr_B1.set_start_timestamp() cr_B1.set_end_timestamp() cr_B1.add_input(iop[0]) cr_B1.add_output(iop[2]) self.store.set_dependencies_from_inputs(cr_B1) self.store.commit_component_run(cr_B1) cr_C1 = self.store.initialize_empty_component_run("test_component_C") cr_C1.set_start_timestamp() cr_C1.set_end_timestamp() cr_C1.add_inputs([iop[1], iop[2]]) cr_C1.add_output(iop[3]) self.store.set_dependencies_from_inputs(cr_C1) self.store.commit_component_run(cr_C1) # Second pipeline cr_C2 = self.store.initialize_empty_component_run("test_component_C") cr_C2.set_start_timestamp() cr_C2.set_end_timestamp() cr_C2.add_inputs([iop[1], iop[2]]) cr_C2.add_output(iop[4]) self.store.set_dependencies_from_inputs(cr_C2) self.store.commit_component_run(cr_C2) # Third pipeline cr_C3 = self.store.initialize_empty_component_run("test_component_C") cr_C3.set_start_timestamp() cr_C3.set_end_timestamp() cr_C3.add_inputs([iop[1], iop[2]]) cr_C3.add_output(iop[5]) self.store.set_dependencies_from_inputs(cr_C3) self.store.commit_component_run(cr_C3) # Fourth pipeline cr_C4 = self.store.initialize_empty_component_run("test_component_C") cr_C4.set_start_timestamp() cr_C4.set_end_timestamp() cr_C4.add_inputs([iop[1], iop[2]]) cr_C4.add_output(iop[6]) self.store.set_dependencies_from_inputs(cr_C4) self.store.commit_component_run(cr_C4) # Flag self.store.set_io_pointer_flag("iop_4", True) self.store.set_io_pointer_flag("iop_5", True) self.store.set_io_pointer_flag("iop_6", True) self.store.set_io_pointer_flag("iop_7", True) _, res = self.store.review_flagged_outputs() res = [(cr.component_name, cr.id, count) for cr, count in res] expected_res = [ ("test_component_B", 2, 4), ("test_component_A", 1, 4), ("test_component_C", 6, 1), ("test_component_C", 5, 1), ("test_component_C", 4, 1), ("test_component_C", 3, 1), ] self.assertEqual(res, expected_res)
class TestDags(unittest.TestCase): def setUp(self): self.store = Store("test") def testLinkedList(self): # Create chain of component runs expected_result = [] num_runs = 10 for i in range(1, num_runs + 1): self.store.create_component(f"mock_component_{i}", "", "") inp = self.store.get_io_pointer(f"iop_{i}") out = self.store.get_io_pointer(f"iop_{i + 1}") cr = self.store.initialize_empty_component_run( f"mock_component_{i}") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(inp) cr.add_output(out) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) expected_result.append((num_runs - i, i)) # Reverse the expected result expected_result.reverse() # Trace the final output trace = self.store.trace("iop_11") level_id = [(l, cr.id) for l, cr in trace] self.assertEqual(expected_result, level_id) def testVersionedComputation(self): # Run the same computation many times self.store.create_component("mock_component", "", "") num_runs = 10 for i in range(1, num_runs + 1): inp = self.store.get_io_pointer("inp") out = self.store.get_io_pointer("out") cr = self.store.initialize_empty_component_run("mock_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(inp) cr.add_output(out) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Trace the out pointer. Only most recent run ID should show. trace = self.store.trace("out") self.assertEqual(len(trace), 1) self.assertEqual(trace[0][0], 0) self.assertEqual(trace[0][1].id, num_runs) def testTree(self): # Create a tree of component runs, 5 levels deep num_levels = 2 global cr_counter global iop_counter cr_counter = 1 iop_counter = 1 def create_tree(level, inp): if level == num_levels: return global cr_counter global iop_counter self.store.create_component(f"mock_component_{cr_counter}", "", "") cr = self.store.initialize_empty_component_run( f"mock_component_{cr_counter}") cr_counter += 1 cr.set_start_timestamp() cr.set_end_timestamp() # Create output pointers out1 = self.store.get_io_pointer(f"iop_{iop_counter}") iop_counter += 1 out2 = self.store.get_io_pointer(f"iop_{iop_counter}") iop_counter += 1 # Add and commit component run cr.add_input(inp) cr.add_outputs([out1, out2]) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Create left and right trees create_tree(level + 1, out1) create_tree(level + 1, out2) # Create first input pointer and tree of computation inp = self.store.get_io_pointer(f"iop_{iop_counter}") iop_counter += 1 create_tree(0, inp) # Grab last iop id and trace it last_iop_id = f"iop_{iop_counter - 1}" trace = self.store.trace(last_iop_id) level_id = [(l, cr.id) for l, cr in trace] self.assertEqual(level_id, [(0, 3), (1, 1)]) def testCycle(self): # Create cycle. Since dependencies are versioned, we shouldn't run into problems. # Create io pointers and components iop1 = self.store.get_io_pointer("iop1") iop2 = self.store.get_io_pointer("iop2") self.store.create_component("component_1", "", "") self.store.create_component("component_2", "", "") # Create component runs cr = self.store.initialize_empty_component_run("component_1") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(iop1) cr.add_output(iop2) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) cr = self.store.initialize_empty_component_run("component_2") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(iop2) cr.add_output(iop1) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Trace iop1 trace_1 = [(l, cr.id) for l, cr in self.store.trace("iop1")] trace_2 = [(l, cr.id) for l, cr in self.store.trace("iop2")] self.assertEqual(trace_1, [(0, 2), (1, 1)]) self.assertEqual(trace_2, [(0, 1)])
class TestStore(unittest.TestCase): def setUp(self): self.store = Store("test") def testComponent(self): self.store.create_component("test_component", "test_description", "shreya") component = self.store.get_component("test_component") self.assertEqual(component.name, "test_component") # Retrieve components with owner components = self.store.get_components_with_owner("shreya") self.assertEqual(1, len(components)) def testCompleteComponentRun(self): # Create component self.store.create_component("test_component", "test_description", "shreya") # Create component run cr = self.store.initialize_empty_component_run("test_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(IOPointer("inp")) cr.add_output(IOPointer("out")) self.store.commit_component_run(cr) # Test retrieval component_runs = self.store.get_history("test_component", limit=None) self.assertEqual(1, len(component_runs)) self.assertEqual(component_runs[0], cr) def testIncompleteComponentRun(self): # Create component self.store.create_component("test_component", "test_description", "shreya") # Create incomplete component run cr = self.store.initialize_empty_component_run("test_component") with self.assertRaises(RuntimeError): self.store.commit_component_run(cr) def testTags(self): # Create component without tags self.store.create_component("test_component", "test_description", "shreya") # Add tags self.store.add_tags_to_component("test_component", ["tag1", "tag2"]) # Test retrieval component = self.store.get_component("test_component") tags = [t.name for t in component.tags] self.assertEqual(component.name, "test_component") self.assertEqual(set(tags), set(["tag1", "tag2"])) def testDuplicateTags(self): # Create component without tags self.store.create_component("test_component", "test_description", "shreya") # Add duplicate tags self.store.add_tags_to_component("test_component", ["tag1", "tag1"]) # Test retrieval component = self.store.get_component("test_component") tags = [t.name for t in component.tags] self.assertEqual(component.name, "test_component") self.assertEqual(tags, ["tag1"]) def testIOPointer(self): # Test there is no IOPointer with self.assertRaises(RuntimeError): self.store.get_io_pointer("iop", create=False) # Create IOPointer iop = self.store.get_io_pointer("iop") iop2 = self.store.get_io_pointer("iop") self.assertEqual(iop, iop2) def testIOPointers(self): # Create new IOPointers from scratch iop_names = [f"iop_{i}" for i in range(100)] iops = self.store.get_io_pointers(iop_names) iops2 = self.store.get_io_pointers(iop_names) self.assertEqual(set(iops), set(iops2)) def testSetDependenciesFromInputs(self): # Create IO pointers inp = self.store.get_io_pointer("inp") out = self.store.get_io_pointer("out") another_out = self.store.get_io_pointer("another_out") # Create two component runs that have the same output self.store.create_component("test_component", "test_description", "shreya") for idx in range(2): cr = self.store.initialize_empty_component_run("test_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(inp) cr.add_output(out) self.store.commit_component_run(cr) # Create another two component runs that have the same output self.store.create_component("test_component", "test_description", "shreya") for idx in range(2): cr = self.store.initialize_empty_component_run("test_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_input(inp) cr.add_output(another_out) self.store.commit_component_run(cr) # Create new component run that depends on "out" pointer cr = self.store.initialize_empty_component_run("test_component") cr.set_start_timestamp() cr.set_end_timestamp() cr.add_inputs([out, another_out]) self.store.set_dependencies_from_inputs(cr) self.store.commit_component_run(cr) # Retrieve latest component run and check dependencies component_runs = self.store.get_history("test_component", limit=None) self.assertTrue(component_runs[1] in component_runs[0].dependencies) self.assertTrue(component_runs[3] in component_runs[0].dependencies) def _set_up_computation(self): # Create dag of computation # Create component and IOPointers self.store.create_component("test_component", "test_description", "shreya") iop = [self.store.get_io_pointer(f"iop_{i}") for i in range(1, 5)] # Create component runs cr1 = self.store.initialize_empty_component_run("test_component") cr1.set_start_timestamp() cr1.set_end_timestamp() cr1.add_output(iop[0]) self.store.set_dependencies_from_inputs(cr1) self.store.commit_component_run(cr1) cr2 = self.store.initialize_empty_component_run("test_component") cr2.set_start_timestamp() cr2.set_end_timestamp() cr2.add_output(iop[0]) self.store.set_dependencies_from_inputs(cr2) self.store.commit_component_run(cr2) cr3 = self.store.initialize_empty_component_run("test_component") cr3.set_start_timestamp() cr3.set_end_timestamp() cr3.add_input(iop[0]) cr3.add_outputs([iop[1], iop[2]]) self.store.set_dependencies_from_inputs(cr3) self.store.commit_component_run(cr3) cr4 = self.store.initialize_empty_component_run("test_component") cr4.set_start_timestamp() cr4.set_end_timestamp() cr4.add_input(iop[2]) cr4.add_output(iop[3]) self.store.set_dependencies_from_inputs(cr4) self.store.commit_component_run(cr4) def testTrace(self): self._set_up_computation() # Call trace functionality trace = self.store.trace("iop_4") level_id = [(l, cr.id) for l, cr in trace] self.assertEqual(level_id, [(0, 4), (1, 3), (2, 2)]) def testEmptyTrace(self): with self.assertRaises(RuntimeError): self.store.trace("some_weird_pointer") with self.assertRaises(RuntimeError): self.store.web_trace("some_weird_pointer") def testWebTrace(self): self._set_up_computation() # Call web trace functionality. The ordering is nondeterministic. expected_res = [ { "id": "componentrun_4", "label": "test_component", "hasCaret": True, "isExpanded": True, "childNodes": [ { "id": "iopointer_iop_4", "label": "iop_4", "hasCaret": False, "parent": "componentrun_4", }, { "id": "componentrun_3", "label": "test_component", "hasCaret": True, "isExpanded": True, "childNodes": [ { "id": "iopointer_iop_2", "label": "iop_2", "hasCaret": False, "parent": "componentrun_3", }, { "id": "iopointer_iop_3", "label": "iop_3", "hasCaret": False, "parent": "componentrun_3", }, { "id": "componentrun_2", "label": "test_component", "hasCaret": True, "isExpanded": True, "childNodes": [ { "id": "iopointer_iop_1", "label": "iop_1", "hasCaret": False, "parent": "componentrun_2", } ], }, ], }, ], } ] web_trace = self.store.web_trace("iop_4") self.assertEqual(web_trace, expected_res)