From af0bc90e4800c0db23c6d2e3b9f9625fd0752ef0 Mon Sep 17 00:00:00 2001 From: Matthias Mair Date: Tue, 24 Jan 2023 23:41:20 +0100 Subject: [PATCH] [BUG] Plugin Schedule do not update when beeing changed + plugin testing (#4243) * Add test for api_call * Add coverage for LocateMixin * no cov for no url * make sure changed details get updated * restructure code * Test that changes in schedules are reflected Fixes #4239 --- InvenTree/plugin/base/integration/mixins.py | 51 ++++++++----------- .../plugin/base/integration/test_mixins.py | 5 ++ .../builtin/barcodes/inventree_barcode.py | 2 +- .../integration/test_scheduled_task.py | 13 +++++ .../samples/locate/test_locate_sample.py | 5 ++ 5 files changed, 45 insertions(+), 31 deletions(-) diff --git a/InvenTree/plugin/base/integration/mixins.py b/InvenTree/plugin/base/integration/mixins.py index 97ca82ea15..5818381fdd 100644 --- a/InvenTree/plugin/base/integration/mixins.py +++ b/InvenTree/plugin/base/integration/mixins.py @@ -153,43 +153,34 @@ class ScheduleMixin: for key, task in self.scheduled_tasks.items(): task_name = self.get_task_name(key) - - if Schedule.objects.filter(name=task_name).exists(): - # Scheduled task already exists - continue! - continue # pragma: no cover - - logger.info(f"Adding scheduled task '{task_name}'") - + obj = { + 'name': task_name, + 'schedule_type': task['schedule'], + 'minutes': task.get('minutes', None), + 'repeats': task.get('repeats', -1), + } func_name = task['func'].strip() if '.' in func_name: """Dotted notation indicates that we wish to run a globally defined function, from a specified Python module.""" - - Schedule.objects.create( - name=task_name, - func=func_name, - schedule_type=task['schedule'], - minutes=task.get('minutes', None), - repeats=task.get('repeats', -1), - ) - + obj['func'] = func_name else: - """ - Non-dotted notation indicates that we wish to call a 'member function' of the calling plugin. - - This is managed by the plugin registry itself. - """ - + """Non-dotted notation indicates that we wish to call a 'member function' of the calling plugin. This is managed by the plugin registry itself.""" slug = self.plugin_slug() + obj['func'] = registry.call_plugin_function + obj['args'] = f"'{slug}', '{func_name}'" - Schedule.objects.create( - name=task_name, - func=registry.call_plugin_function, - args=f"'{slug}', '{func_name}'", - schedule_type=task['schedule'], - minutes=task.get('minutes', None), - repeats=task.get('repeats', -1), - ) + if Schedule.objects.filter(name=task_name).exists(): + # Scheduled task already exists - update it! + logger.info(f"Updating scheduled task '{task_name}'") + instance = Schedule.objects.get(name=task_name) + for item in obj: + setattr(instance, item, obj[item]) + instance.save() + else: + logger.info(f"Adding scheduled task '{task_name}'") + # Create a new scheduled task + Schedule.objects.create(**obj) except (ProgrammingError, OperationalError): # pragma: no cover # Database might not yet be ready diff --git a/InvenTree/plugin/base/integration/test_mixins.py b/InvenTree/plugin/base/integration/test_mixins.py index b5af8e95fe..40c073413a 100644 --- a/InvenTree/plugin/base/integration/test_mixins.py +++ b/InvenTree/plugin/base/integration/test_mixins.py @@ -271,6 +271,11 @@ class APICallMixinTest(BaseMixinDefinition, TestCase): self.assertTrue(result) self.assertEqual(result['name'], 'morpheus') + # api_call with endpoint with leading slash + result = self.mixin.api_call('/orgs/inventree', simple_response=False) + self.assertTrue(result) + self.assertEqual(result.reason, 'OK') + # api_call with filter result = self.mixin.api_call('repos/inventree/InvenTree/stargazers', url_args={'page': '2'}) self.assertTrue(result) diff --git a/InvenTree/plugin/builtin/barcodes/inventree_barcode.py b/InvenTree/plugin/builtin/barcodes/inventree_barcode.py index 4e6a6fae50..36a253086e 100644 --- a/InvenTree/plugin/builtin/barcodes/inventree_barcode.py +++ b/InvenTree/plugin/builtin/barcodes/inventree_barcode.py @@ -55,7 +55,7 @@ class InvenTreeInternalBarcodePlugin(BarcodeMixin, InvenTreePlugin): url = instance.get_absolute_url() data['web_url'] = url else: - url = None + url = None # pragma: no cover response = { label: data diff --git a/InvenTree/plugin/samples/integration/test_scheduled_task.py b/InvenTree/plugin/samples/integration/test_scheduled_task.py index 32627c0aa9..7e433178f1 100644 --- a/InvenTree/plugin/samples/integration/test_scheduled_task.py +++ b/InvenTree/plugin/samples/integration/test_scheduled_task.py @@ -31,6 +31,19 @@ class ExampleScheduledTaskPluginTests(TestCase): scheduled_plugin_tasks = Schedule.objects.filter(name__istartswith="plugin.") self.assertEqual(len(scheduled_plugin_tasks), 3) + # test updating the schedule + hello_schedule = Schedule.objects.get(name='plugin.schedule.hello') + self.assertEqual(hello_schedule.minutes, 45) + # change the schedule and reregister + plg.scheduled_tasks['hello']['minutes'] = 15 + plg.register_tasks() + + # Check that the schedule was updated + hello_schedule = Schedule.objects.get(name='plugin.schedule.hello') + scheduled_plugin_tasks = Schedule.objects.filter(name__istartswith="plugin.") + self.assertEqual(hello_schedule.minutes, 15) + self.assertEqual(len(scheduled_plugin_tasks), 3) + # delete middle task # this is to check the system also deals with disappearing tasks scheduled_plugin_tasks[1].delete() diff --git a/InvenTree/plugin/samples/locate/test_locate_sample.py b/InvenTree/plugin/samples/locate/test_locate_sample.py index 1e85ceb566..2221accbd9 100644 --- a/InvenTree/plugin/samples/locate/test_locate_sample.py +++ b/InvenTree/plugin/samples/locate/test_locate_sample.py @@ -51,9 +51,14 @@ class SampleLocatePlugintests(InvenTreeAPITestCase): def test_mixin(self): """Test that MixinNotImplementedError is raised.""" + # Test location locator with self.assertRaises(MixinNotImplementedError): class Wrong(LocateMixin, InvenTreePlugin): pass plugin = Wrong() plugin.locate_stock_location(1) + + # Test item locator + with self.assertRaises(MixinNotImplementedError): + plugin.locate_stock_item(1)