Example #1
0
    def test_add_undo_selected(self):
        """Undoing an add sets selection."""
        self.tab.wf_modules.create(
            order=0,
            last_relevant_delta_id=self.delta.id,
            params={'url': ''}
        )

        # beginning state: one WfModule
        all_modules = self.tab.live_wf_modules
        self.assertEqual(all_modules.count(), 1)

        cmd = self.run_with_async_db(AddModuleCommand.create(
            workflow=self.workflow,
            tab=self.workflow.tabs.first(),
            module_id_name=self.module_version.id_name,
            position=1,
            param_values={}
        ))

        self.tab.selected_wf_module_position = 1
        self.tab.save(update_fields=['selected_wf_module_position'])

        self.run_with_async_db(cmd.backward())

        self.tab.refresh_from_db()
        self.assertEqual(self.tab.selected_wf_module_position, 0)
    def test_add_to_empty_tab_affects_dependent_tab_wf_modules(self):
        ModuleVersion.create_or_replace_from_spec({
            'id_name':
            'tabby',
            'name':
            'Tabby',
            'category':
            'Clean',
            'parameters': [{
                'id_name': 'tab',
                'type': 'tab'
            }]
        })

        wfm1 = self.workflow.tabs.first().wf_modules.create(
            order=0,
            module_id_name='tabby',
            last_relevant_delta_id=self.workflow.last_delta_id,
            params={'tab': 'tab-2'})

        tab2 = self.workflow.tabs.create(position=1, slug='tab-2')

        # Now add a module to tab2.
        cmd = self.run_with_async_db(
            AddModuleCommand.create(workflow=self.workflow,
                                    tab=tab2,
                                    module_id_name=self.module_version.id_name,
                                    position=0,
                                    param_values={'url': 'https://x.com'}))

        # Tab1's "tabby" module depends on tab2, so it should update.
        wfm1.refresh_from_db()
        self.assertEqual(wfm1.last_relevant_delta_id, cmd.id)
Example #3
0
    def test_add_module_validate_params(self):
        workflow = Workflow.create_and_init()
        module_version = ModuleVersion.create_or_replace_from_spec(
            {
                "id_name": "blah",
                "name": "Blah",
                "category": "Clean",
                "parameters": [{
                    "id_name": "a",
                    "type": "string"
                }],
            },
            source_version_hash="1.0",
        )

        with self.assertRaises(ValueError):
            self.run_with_async_db(
                AddModuleCommand.create(
                    workflow=workflow,
                    tab=workflow.tabs.first(),
                    slug="step-1",
                    module_id_name=module_version.id_name,
                    position=0,
                    param_values={"a": 3},
                ))
Example #4
0
    def test_add_module_default_params(self):
        workflow = Workflow.create_and_init()
        module_version = ModuleVersion.create_or_replace_from_spec(
            {
                'id_name':
                'blah',
                'name':
                'Blah',
                'category':
                'Clean',
                'parameters': [
                    {
                        'id_name': 'a',
                        'type': 'string',
                        'default': 'x'
                    },
                    {
                        'id_name': 'c',
                        'type': 'checkbox',
                        'name': 'C',
                        'default': True
                    },
                ],
            },
            source_version_hash='1.0')

        cmd = self.run_with_async_db(
            AddModuleCommand.create(workflow=workflow,
                                    tab=workflow.tabs.first(),
                                    module_id_name=module_version.id_name,
                                    position=0,
                                    param_values={}))
        self.assertEqual(cmd.wf_module.params, {'a': 'x', 'c': True})
Example #5
0
 def test_delete_if_workflow_delete_cascaded_to_wf_module_first(self):
     self.run_with_async_db(
         AddModuleCommand.create(workflow=self.workflow,
                                 tab=self.workflow.tabs.first(),
                                 module_id_name=self.module_version.id_name,
                                 position=0,
                                 param_values={}))
     # Add a second command -- so we test what happens when deleting
     # multiple deltas while deleting the workflow.
     self.run_with_async_db(
         AddModuleCommand.create(workflow=self.workflow,
                                 tab=self.workflow.tabs.first(),
                                 module_id_name=self.module_version.id_name,
                                 position=0,
                                 param_values={}))
     self.workflow.delete()
     self.assertTrue(True)  # we didn't crash! Yay, we pass
Example #6
0
 def test_add_module_raise_module_version_does_not_exist(self):
     workflow = Workflow.create_and_init()
     with self.assertRaises(ModuleVersion.DoesNotExist):
         self.run_with_async_db(
             AddModuleCommand.create(workflow=workflow,
                                     tab=workflow.tabs.first(),
                                     module_id_name='doesnotexist',
                                     position=0,
                                     param_values={}))
Example #7
0
    def test_add_module(self):
        existing_module = self.tab.wf_modules.create(
            order=0, last_relevant_delta_id=self.delta.id, params={'url': ''})

        all_modules = self.tab.live_wf_modules

        self.workflow.refresh_from_db()
        v1 = self.workflow.last_delta_id

        # Add a module, insert before the existing one, check to make sure it
        # went there and old one is after
        cmd = self.run_with_async_db(
            AddModuleCommand.create(workflow=self.workflow,
                                    tab=self.workflow.tabs.first(),
                                    module_id_name=self.module_version.id_name,
                                    position=0,
                                    param_values={'url': 'https://x.com'}))
        self.assertEqual(all_modules.count(), 2)
        added_module = all_modules.get(order=0)
        self.assertNotEqual(added_module, existing_module)
        # Test that supplied param is written
        self.assertEqual(added_module.params['url'], 'https://x.com')
        bumped_module = all_modules.get(order=1)
        self.assertEqual(bumped_module, existing_module)

        # workflow revision should have been incremented
        self.workflow.refresh_from_db()
        self.assertGreater(self.workflow.last_delta_id, v1)

        # Check the delta chain (short, but should be sweet)
        self.workflow.refresh_from_db()
        self.assertEqual(self.workflow.last_delta, cmd)
        self.assertEqual(cmd.prev_delta_id, self.delta.id)
        with self.assertRaises(Delta.DoesNotExist):
            cmd.next_delta

        # undo! undo! ahhhhh everything is on fire! undo!
        self.run_with_async_db(cmd.backward())
        self.assertEqual(all_modules.count(), 1)
        self.assertEqual(all_modules.first(), existing_module)

        # wait no, we wanted that module
        self.run_with_async_db(cmd.forward())
        self.assertEqual(all_modules.count(), 2)
        added_module = all_modules.get(order=0)
        self.assertNotEqual(added_module, existing_module)
        bumped_module = all_modules.get(order=1)
        self.assertEqual(bumped_module, existing_module)

        # Undo and test deleting the un-applied command. Should delete dangling
        # WfModule too
        self.run_with_async_db(cmd.backward())
        self.assertEqual(all_modules.count(), 1)
        self.assertEqual(all_modules.first(), existing_module)
        cmd.delete_with_successors()
        with self.assertRaises(WfModule.DoesNotExist):
            all_modules.get(pk=added_module.id)  # should be gone
Example #8
0
 def test_add_delete(self):
     cmda = self.run_with_async_db(
         AddModuleCommand.create(workflow=self.workflow,
                                 tab=self.workflow.tabs.first(),
                                 module_id_name=self.module_version.id_name,
                                 position=0,
                                 param_values={}))
     self.run_with_async_db(
         DeleteModuleCommand.create(workflow=self.workflow,
                                    wf_module=cmda.wf_module))
     self.workflow.delete()
     self.assertTrue(True)  # we didn't crash! Yay, we pass
Example #9
0
    def test_delete_if_workflow_missing_init(self):
        self.workflow.last_delta_id = None
        self.workflow.save(update_fields=['last_delta_id'])

        self.delta.delete()
        self.run_with_async_db(
            AddModuleCommand.create(workflow=self.workflow,
                                    tab=self.workflow.tabs.first(),
                                    module_id_name=self.module_version.id_name,
                                    position=0,
                                    param_values={}))

        self.workflow.delete()
        self.assertTrue(True)  # we didn't crash! Yay, we pass
Example #10
0
    def test_undo_add_only_selected(self):
        """Undoing the only add sets selection to None."""
        cmd = self.run_with_async_db(
            AddModuleCommand.create(workflow=self.workflow,
                                    tab=self.workflow.tabs.first(),
                                    module_id_name=self.module_version.id_name,
                                    position=0,
                                    param_values={}))

        self.tab.selected_wf_module_position = 0
        self.tab.save(update_fields=['selected_wf_module_position'])

        self.run_with_async_db(cmd.backward())

        self.tab.refresh_from_db()
        self.assertIsNone(self.tab.selected_wf_module_position)
Example #11
0
 def test_add_module_raise_slug_not_unique(self):
     workflow = Workflow.create_and_init()
     tab = workflow.tabs.first()
     tab.wf_modules.create(order=0, slug="step-1", module_id_name="x")
     # module_id_name doesn't exist either, but we'll white-box test and
     # assume the uniqueness check comes first
     with self.assertRaisesRegex(ValueError, "unique"):
         self.run_with_async_db(
             AddModuleCommand.create(
                 workflow=workflow,
                 tab=tab,
                 slug="step-1",
                 module_id_name="x",
                 position=0,
                 param_values={},
             ))
Example #12
0
    def test_add_module_validate_params(self):
        workflow = Workflow.create_and_init()
        module_version = ModuleVersion.create_or_replace_from_spec({
            'id_name': 'blah',
            'name': 'Blah',
            'category': 'Clean',
            'parameters': [
                {'id_name': 'a', 'type': 'string'}
            ]
        }, source_version_hash='1.0')

        with self.assertRaises(ValueError):
            self.run_with_async_db(AddModuleCommand.create(
                workflow=workflow,
                tab=workflow.tabs.first(),
                module_id_name=module_version.id_name,
                position=0,
                param_values={'a': 3}
            ))
Example #13
0
    def test_add_to_empty_tab_affects_dependent_tab_wf_modules(self):
        ModuleVersion.create_or_replace_from_spec({
            "id_name":
            "tabby",
            "name":
            "Tabby",
            "category":
            "Clean",
            "parameters": [{
                "id_name": "tab",
                "type": "tab"
            }],
        })

        wfm1 = self.workflow.tabs.first().wf_modules.create(
            order=0,
            slug="step-1",
            module_id_name="tabby",
            last_relevant_delta_id=self.workflow.last_delta_id,
            params={"tab": "tab-2"},
        )

        tab2 = self.workflow.tabs.create(position=1, slug="tab-2")

        # Now add a module to tab2.
        cmd = self.run_with_async_db(
            AddModuleCommand.create(
                workflow=self.workflow,
                tab=tab2,
                slug="step-2",
                module_id_name=self.module_version.id_name,
                position=0,
                param_values={"url": "https://x.com"},
            ))

        # Tab1's "tabby" module depends on tab2, so it should update.
        wfm1.refresh_from_db()
        self.assertEqual(wfm1.last_relevant_delta_id, cmd.id)
Example #14
0
 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
Example #15
0
    def test_add_module_default_params(self):
        workflow = Workflow.create_and_init()
        module_version = ModuleVersion.create_or_replace_from_spec(
            {
                "id_name":
                "blah",
                "name":
                "Blah",
                "category":
                "Clean",
                "parameters": [
                    {
                        "id_name": "a",
                        "type": "string",
                        "default": "x"
                    },
                    {
                        "id_name": "c",
                        "type": "checkbox",
                        "name": "C",
                        "default": True
                    },
                ],
            },
            source_version_hash="1.0",
        )

        cmd = self.run_with_async_db(
            AddModuleCommand.create(
                workflow=workflow,
                tab=workflow.tabs.first(),
                slug="step-1",
                module_id_name=module_version.id_name,
                position=0,
                param_values={},
            ))
        self.assertEqual(cmd.wf_module.params, {"a": "x", "c": True})
Example #16
0
 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
Example #17
0
    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])
Example #18
0
    def test_add_many_modules(self):
        existing_module = self.tab.wf_modules.create(
            order=0, last_relevant_delta_id=self.delta.id, params={'url': ''})

        self.workflow.refresh_from_db()
        v1 = self.workflow.last_delta_id

        # beginning state: one WfModule
        all_modules = self.tab.live_wf_modules

        # Insert at beginning
        cmd1 = self.run_with_async_db(
            AddModuleCommand.create(workflow=self.workflow,
                                    tab=self.workflow.tabs.first(),
                                    module_id_name=self.module_version.id_name,
                                    position=0,
                                    param_values={}))
        v2 = cmd1.id
        self.assertEqual(all_modules.count(), 2)
        self.assertEqual(cmd1.wf_module.order, 0)
        self.assertNotEqual(cmd1.wf_module, existing_module)
        v2 = cmd1.id
        self.assertWfModuleVersions([v2, v2])

        # Insert at end
        cmd2 = self.run_with_async_db(
            AddModuleCommand.create(workflow=self.workflow,
                                    tab=self.workflow.tabs.first(),
                                    module_id_name=self.module_version.id_name,
                                    position=2,
                                    param_values={}))
        v3 = cmd2.id
        self.assertEqual(all_modules.count(), 3)
        self.assertEqual(cmd2.wf_module.order, 2)
        self.assertWfModuleVersions([v2, v2, v3])

        # Insert in between two modules
        cmd3 = self.run_with_async_db(
            AddModuleCommand.create(workflow=self.workflow,
                                    tab=self.workflow.tabs.first(),
                                    module_id_name=self.module_version.id_name,
                                    position=2,
                                    param_values={}))
        v4 = cmd3.id
        self.assertEqual(all_modules.count(), 4)
        self.assertEqual(cmd3.wf_module.order, 2)
        self.assertWfModuleVersions([v2, v2, v4, v4])

        # Check the delta chain, should be 1 <-> 2 <-> 3
        self.workflow.refresh_from_db()
        cmd1.refresh_from_db()
        cmd2.refresh_from_db()
        cmd3.refresh_from_db()
        self.assertEqual(self.workflow.last_delta, cmd3)
        with self.assertRaises(Delta.DoesNotExist):
            cmd3.next_delta
        self.assertEqual(cmd3.prev_delta, cmd2)
        self.assertEqual(cmd2.prev_delta, cmd1)
        self.assertEqual(cmd1.prev_delta_id, self.delta.id)

        # We should be able to go all the way back
        self.run_with_async_db(cmd3.backward())
        self.assertWfModuleVersions([v2, v2, v3])
        self.run_with_async_db(cmd2.backward())
        self.assertWfModuleVersions([v2, v2])
        self.run_with_async_db(cmd1.backward())
        self.assertWfModuleVersions([v1])
        self.assertEqual(list(all_modules.values_list('id', flat=True)),
                         [existing_module.id])