def test_delete_ignores_other_workflows(self): workflow = Workflow.create_and_init() workflow2 = Workflow.create_and_init() # Create a delta we want to delete delta = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="1")) # Create deltas on workflow2 that we _don't_ want to delete delta2 = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow2, new_value="1")) self.run_with_async_db(delta.backward()) # fix workflow.last_delta_id delta.delete_with_successors() workflow.delete_orphan_soft_deleted_models() delta2.refresh_from_db() # do not crash
def test_delete_orphans(self): workflow = Workflow.create_and_init() self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="1")) delta2 = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="2")) delta3 = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="3")) self.run_with_async_db(delta3.backward()) self.run_with_async_db(delta2.backward()) # Create a new delta ... making delta2 and delta3 obsolete self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="4")) with self.assertRaises(Delta.DoesNotExist): delta2.refresh_from_db() with self.assertRaises(Delta.DoesNotExist): delta3.refresh_from_db()
def test_delete_deltas_without_init_delta(self): workflow = Workflow.objects.create(name='A') tab = workflow.tabs.create(position=0) self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value='B')) ModuleVersion.create_or_replace_from_spec({ 'id_name': 'x', 'name': 'x', 'category': 'Clean', 'parameters': [], }) self.run_with_async_db( AddModuleCommand.create(workflow=workflow, tab=tab, module_id_name='x', position=0, param_values={})) self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value='C')) workflow.delete() self.assertTrue(True) # no crash
def test_delete_deletes_soft_deleted_wfmodule(self): workflow = Workflow.create_and_init() # Here's a soft-deleted module wf_module = workflow.tabs.first().wf_modules.create( order=0, slug="step-1", module_id_name="foo", is_deleted=True) delta = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="1")) self.run_with_async_db(delta.backward()) # fix workflow.last_delta_id delta.delete_with_successors() workflow.delete_orphan_soft_deleted_models() with self.assertRaises(WfModule.DoesNotExist): wf_module.refresh_from_db()
def test_delete_protects_non_deleted_wfmodule(self): workflow = Workflow.create_and_init() # Here's a soft-deleted module wf_module = workflow.tabs.first().wf_modules.create( order=0, slug="step-1", module_id_name="foo", is_deleted=False) # delete a delta delta = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="1")) self.run_with_async_db(delta.backward()) # fix workflow.last_delta_id delta.delete_with_successors() workflow.delete_orphan_soft_deleted_models() wf_module.refresh_from_db() # no DoesNotExist: it's not deleted
def test_delete_deltas_without_init_delta(self): workflow = Workflow.objects.create(name="A") tab = workflow.tabs.create(position=0) self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="B") ) ModuleVersion.create_or_replace_from_spec( {"id_name": "x", "name": "x", "category": "Clean", "parameters": []} ) self.run_with_async_db( AddModuleCommand.create( workflow=workflow, tab=tab, slug="step-1", module_id_name="x", position=0, param_values={}, ) ) self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="C") ) workflow.delete() self.assertTrue(True) # no crash
def test_delete_scopes_tab_delete_by_workflow(self): workflow = Workflow.create_and_init() workflow2 = Workflow.create_and_init() # Here's a soft-deleted module on workflow2. Nothing references it. It # "shouldn't" exist. tab = workflow2.tabs.create(position=1) # now delete a delta on workflow1 delta = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="1")) self.run_with_async_db(delta.backward()) # fix workflow.last_delta_id delta.delete_with_successors() workflow.delete_orphan_soft_deleted_models() tab.refresh_from_db() # no DoesNotExist: leave workflow2 alone
def test_delete_scopes_wf_module_delete_by_workflow(self): workflow = Workflow.create_and_init() workflow2 = Workflow.create_and_init() # Here's a soft-deleted module on workflow2. Nothing references it. It # "shouldn't" exist. wf_module = workflow2.tabs.first().wf_modules.create( order=0, slug="step-1", module_id_name="foo", is_deleted=True) # now delete a delta on workflow1 delta = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="1")) self.run_with_async_db(delta.backward()) # fix workflow.last_delta_id delta.delete_with_successors() workflow.delete_orphan_soft_deleted_models() wf_module.refresh_from_db() # no DoesNotExist: leave workflow2 alone
def test_delete_deletes_soft_deleted_tab(self): workflow = Workflow.create_and_init() tab = workflow.tabs.create(position=1, is_deleted=True) # create a wf_module -- it needs to be deleted, too! wf_module = tab.wf_modules.create(order=0, module_id_name='foo', is_deleted=True) delta = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value='1')) self.run_with_async_db(delta.backward()) # fix workflow.last_delta_id delta.delete_with_successors() workflow.delete_orphan_soft_deleted_models() with self.assertRaises(WfModule.DoesNotExist): wf_module.refresh_from_db() with self.assertRaises(Tab.DoesNotExist): tab.refresh_from_db()
def test_delete_protects_soft_deleted_wfmodule_with_reference(self): workflow = Workflow.create_and_init() # Here's a soft-deleted module wf_module = workflow.tabs.first().wf_modules.create( order=0, slug="step-1", module_id_name="foo", is_deleted=True) # "protect" it: here's a delta we _aren't_ deleting self.run_with_async_db( ChangeWfModuleNotesCommand.create(workflow=workflow, wf_module=wf_module, new_value="1")) # now delete a delta delta = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="1")) self.run_with_async_db(delta.backward()) # fix workflow.last_delta_id delta.delete_with_successors() workflow.delete_orphan_soft_deleted_models() wf_module.refresh_from_db() # no DoesNotExist -- a delta depends on it
def test_change_title(self): workflow = Workflow.create_and_init(name="title1") # Change back to second title, see if it saved cmd = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value="title2")) self.assertEqual(workflow.name, "title2") # test var change workflow.refresh_from_db() self.assertEqual(workflow.name, "title2") # test DB change # undo self.run_with_async_db(cmd.backward()) self.assertEqual(workflow.name, "title1") # test var change workflow.refresh_from_db() self.assertEqual(workflow.name, "title1") # test DB change # redo self.run_with_async_db(cmd.forward()) self.assertEqual(workflow.name, "title2") workflow.refresh_from_db() self.assertEqual(workflow.name, "title2")
def test_undo_redo(self): ModuleVersion.create_or_replace_from_spec({ 'id_name': 'pastecsv', 'name': 'pastecsv', 'category': 'Clean', 'parameters': [ { 'id_name': 'csv', 'type': 'string' }, ] }) workflow = Workflow.create_and_init() tab = workflow.tabs.first() all_modules = tab.live_wf_modules # beginning state: nothing v0 = workflow.last_delta_id # Test undoing nothing at all. Should NOP self.run_with_async_db(WorkflowUndo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta_id, v0) self.assertEqual(all_modules.count(), 0) self.assertEqual(workflow.last_delta_id, v0) # Add a module cmd1 = self.run_with_async_db( AddModuleCommand.create(workflow=workflow, tab=tab, module_id_name='pastecsv', position=0, param_values={})) v1 = cmd1.id workflow.refresh_from_db() self.assertEqual(all_modules.count(), 1) self.assertGreater(v1, v0) self.assertEqual(workflow.last_delta_id, v1) self.assertWfModuleVersions(tab, [v1]) # Undo, ensure we are back at start self.run_with_async_db(WorkflowUndo(workflow)) workflow.refresh_from_db() self.assertEqual(all_modules.count(), 0) self.assertEqual(workflow.last_delta_id, v0) self.assertWfModuleVersions(tab, []) # Redo, ensure we are back at v1 self.run_with_async_db(WorkflowRedo(workflow)) workflow.refresh_from_db() self.assertEqual(all_modules.count(), 1) self.assertEqual(workflow.last_delta_id, v1) self.assertWfModuleVersions(tab, [v1]) # Change a parameter cmd2 = self.run_with_async_db( ChangeParametersCommand.create( workflow=workflow, wf_module=tab.live_wf_modules.first(), new_values={'csv': 'some value'})) v2 = cmd2.id workflow.refresh_from_db() self.assertEqual(tab.live_wf_modules.first().params['csv'], 'some value') self.assertEqual(workflow.last_delta_id, v2) self.assertGreater(v2, v1) self.assertWfModuleVersions(tab, [v2]) # Undo parameter change self.run_with_async_db(WorkflowUndo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta_id, v1) self.assertEqual(tab.live_wf_modules.first().params['csv'], '') self.assertWfModuleVersions(tab, [v1]) # Redo self.run_with_async_db(WorkflowRedo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta_id, v2) self.assertEqual(tab.live_wf_modules.first().params['csv'], 'some value') self.assertWfModuleVersions(tab, [v2]) # Redo again should do nothing self.run_with_async_db(WorkflowRedo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta_id, v2) self.assertEqual(tab.live_wf_modules.first().params['csv'], 'some value') self.assertWfModuleVersions(tab, [v2]) # Add one more command so the stack is 3 deep cmd3 = self.run_with_async_db( ChangeWorkflowTitleCommand.create(workflow=workflow, new_value='New Title')) v3 = cmd3.id self.assertGreater(v3, v2) self.assertWfModuleVersions(tab, [v2]) # Undo twice self.run_with_async_db(WorkflowUndo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta, cmd2) self.assertWfModuleVersions(tab, [v2]) self.run_with_async_db(WorkflowUndo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta, cmd1) self.assertWfModuleVersions(tab, [v1]) # Redo twice self.run_with_async_db(WorkflowRedo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta, cmd2) self.assertWfModuleVersions(tab, [v2]) self.run_with_async_db(WorkflowRedo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta, cmd3) self.assertWfModuleVersions(tab, [v2]) # Undo again to get to a place where we have two commands to redo self.run_with_async_db(WorkflowUndo(workflow)) self.run_with_async_db(WorkflowUndo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta, cmd1) # Now add a new command. It should remove cmd2, cmd3 from the redo # stack and delete them from the db wfm = all_modules.first() cmd4 = self.run_with_async_db( ChangeWfModuleNotesCommand.create(workflow=workflow, wf_module=wfm, new_value='Note of no note')) v4 = cmd4.id workflow.refresh_from_db() self.assertEqual(workflow.last_delta_id, v4) self.assertEqual(set(Delta.objects.values_list('id', flat=True)), {v0, v1, v4}) # v2, v3 deleted # Undo back to start, then add a command, ensure it deletes dangling # commands (tests an edge case in Delta.save) self.run_with_async_db(WorkflowUndo(workflow)) workflow.refresh_from_db() self.assertEqual(workflow.last_delta_id, v1) cmd5 = self.run_with_async_db( ChangeWfModuleNotesCommand.create(workflow=workflow, wf_module=cmd1.wf_module, new_value='Note of some note')) v5 = cmd5.id workflow.refresh_from_db() self.assertEqual(workflow.last_delta_id, v5) self.assertEqual(set(Delta.objects.values_list('id', flat=True)), {v0, v1, v5}) # v1, v4 deleted self.assertWfModuleVersions(tab, [v1])