add tests

This commit is contained in:
Arthur 2026-09-03 10:24:57 -07:00
parent 8c697161b7
commit 7cff6a27d4
2 changed files with 102 additions and 1 deletions

View File

@ -1907,6 +1907,7 @@ class ScriptRunExecutionTestCase(APITestCase):
site = ObjectVar(model=Site)
sites = MultiObjectVar(model=Site, required=False)
label = StringVar(default='hello')
flag = BooleanVar(default=True)
def run(self, data, commit=True):
return 'ok'
@ -2046,6 +2047,55 @@ class ScriptRunExecutionTestCase(APITestCase):
self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
mock_enqueue.assert_not_called()
@patch('extras.jobs.ScriptJob.enqueue')
def test_run_ignores_undeclared_keys(self, mock_enqueue):
# Binding 'data' to the script's form means keys which don't correspond to a declared
# variable are dropped rather than forwarded to run(). This is the contract documented
# under "Running Custom Scripts > Via the API"; pin it so it can't regress silently.
payload = {
'data': {'site': self.sites[0].pk, 'bogus': 'ignored', 'id': 99},
'commit': True,
}
response = self.client.post(self.url, payload, format='json', **self.header)
self.assertHttpStatus(response, status.HTTP_200_OK)
data = mock_enqueue.call_args.kwargs['data']
self.assertEqual(data['site'], self.sites[0])
self.assertNotIn('bogus', data)
self.assertNotIn('id', data)
@patch('extras.jobs.ScriptJob.enqueue')
def test_run_rejects_omitted_required_var(self, mock_enqueue):
# 'site' is required and declares no default, so unlike 'label' it cannot be
# back-filled: omitting it must 400 rather than enqueue a job that fails at runtime.
payload = {'data': {'label': 'hi'}, 'commit': True}
response = self.client.post(self.url, payload, format='json', **self.header)
self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
self.assertIn('site', response.data['data'])
mock_enqueue.assert_not_called()
@patch('extras.jobs.ScriptJob.enqueue')
def test_run_resolves_booleanvar_default_and_explicit_values(self, mock_enqueue):
# BooleanVar renders as a checkbox, and CheckboxInput reads a missing key as False.
# An omitted BooleanVar must therefore pick up its declared default, while an
# explicitly supplied False must not be overwritten by that default.
for case, supplied, expected in (
('omitted', {}, True),
('explicit False', {'flag': False}, False),
('explicit True', {'flag': True}, True),
):
with self.subTest(case=case):
mock_enqueue.reset_mock()
payload = {'data': {'site': self.sites[0].pk, **supplied}, 'commit': True}
response = self.client.post(self.url, payload, format='json', **self.header)
self.assertHttpStatus(response, status.HTTP_200_OK)
self.assertIs(mock_enqueue.call_args.kwargs['data']['flag'], expected)
class CreatedUpdatedFilterTestCase(APITestCase):

View File

@ -14,7 +14,7 @@ from core.models import Job, ObjectType
from dcim.models import DeviceType, Manufacturer, Site
from extras.choices import *
from extras.models import *
from extras.scripts import BooleanVar, IntegerVar
from extras.scripts import BooleanVar, IntegerVar, StringVar
from extras.scripts import Script as PythonClass
from users.models import Group, ObjectPermission, User
from utilities.testing import TestCase, ViewTestCases
@ -1279,6 +1279,57 @@ class ScriptModuleCreateViewTestCase(TestCase):
self.assertEqual(response.context['return_url'], reverse('extras:script_list'))
class ScriptDefaultBackfillTestCase(TestCase):
"""
The UI and the REST API now share prepare_script_form(), so the UI's back-filling of
declared defaults (previously inline in ScriptView.post()) must keep working after
that logic moved into the helper.
"""
user_permissions = ['extras.view_script', 'extras.run_script']
class TestScriptClass(PythonClass):
class Meta:
name = 'Backfill test'
commit_default = False
label = StringVar(default='hello')
flag = BooleanVar(default=True)
def run(self, data, commit):
return 'Complete'
@classmethod
def setUpTestData(cls):
with patch.object(ScriptModule, 'sync_classes'):
module = ScriptModule.objects.create(
file_root=ManagedFileRootPathChoices.SCRIPTS,
file_path='backfill_script.py',
)
cls.script = Script.objects.create(module=module, name='Backfill test', is_executable=True)
def setUp(self):
super().setUp()
python_class_patch = patch.object(Script, 'python_class', new=self.TestScriptClass)
python_class_patch.start()
self.addCleanup(python_class_patch.stop)
@tag('regression')
def test_ui_backfills_declared_defaults(self):
url = reverse('extras:script', kwargs={'pk': self.script.pk})
with (
patch('extras.views.any_workers_for_queue', return_value=True),
patch('extras.jobs.ScriptJob.enqueue') as mock_enqueue,
):
mock_enqueue.return_value.pk = 1
response = self.client.post(url, {'_commit': 'true'})
self.assertEqual(response.status_code, 302)
data = mock_enqueue.call_args.kwargs['data']
self.assertEqual(data['label'], 'hello')
self.assertIs(data['flag'], True)
class ScriptValidationErrorTestCase(TestCase):
user_permissions = ['extras.view_script', 'extras.run_script']