content: import datetime
  
  from django.contrib.contenttypes.models import ContentType
  from django.urls import reverse
  from django.utils.timezone import make_aware, now
  from rest_framework import status
  
  from core.choices import ManagedFileRootPathChoices
  from core.events import *
  from core.models import ObjectType
  from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Rack, Location, RackRole, Site
  from extras.choices import *
  from extras.models import *
  from extras.scripts import BooleanVar, IntegerVar, Script as PythonClass, StringVar
  from users.models import Group, User
  from utilities.testing import APITestCase, APIViewTestCases
  
  
  class AppTest(APITestCase):
  
      def test_root(self):
  
          url = reverse('extras-api:api-root')
          response = self.client.get('{}?format=api'.format(url), **self.header)
  
          self.assertEqual(response.status_code, 200)
  
  
  class WebhookTest(APIViewTestCases.APIViewTestCase):
      model = Webhook
      brief_fields = ['description', 'display', 'id', 'name', 'url']
      create_data = [
          {
              'name': 'Webhook 4',
              'payload_url': 'http://example.com/?4',
          },
          {
              'name': 'Webhook 5',
              'payload_url': 'http://example.com/?5',
          },
          {
              'name': 'Webhook 6',
              'payload_url': 'http://example.com/?6',
          },
      ]
      bulk_update_data = {
          'description': 'New description',
          'ssl_verification': False,
      }
  
      @classmethod
      def setUpTestData(cls):
  
          webhooks = (
              Webhook(
                  name='Webhook 1',
                  payload_url='http://example.com/?1',
              ),
              Webhook(
                  name='Webhook 2',
                  payload_url='http://example.com/?1',
              ),
              Webhook(
                  name='Webhook 3',
                  payload_url='http://example.com/?1',
              ),
          )
          Webhook.objects.bulk_create(webhooks)
  
  
  class EventRuleTest(APIViewTestCases.APIViewTestCase):
      model = EventRule
      brief_fields = ['description', 'display', 'id', 'name', 'url']
      bulk_update_data = {
          'enabled': False,
          'description': 'New description',
      }
      update_data = {
          'name': 'Event Rule X',
          'enabled': False,
          'description': 'New description',
      }
  
      @classmethod
      def setUpTestData(cls):
          webhooks = (
              Webhook(
                  name='Webhook 1',
                  payload_url='http://example.com/?1',
              ),
              Webhook(
                  name='Webhook 2',
                  payload_url='http://example.com/?1',
              ),
              Webhook(
                  name='Webhook 3',
                  payload_url='http://example.com/?1',
              ),
              Webhook(
                  name='Webhook 4',
                  payload_url='http://example.com/?1',
              ),
              Webhook(
                  name='Webhook 5',
                  payload_url='http://example.com/?1',
              ),
              Webhook(
                  name='Webhook 6',
                  payload_url='http://example.com/?1',
              ),
          )
          Webhook.objects.bulk_create(webhooks)
  
          event_rules = (
              EventRule(name='EventRule 1', event_types=[OBJECT_CREATED], action_object=webhooks[0]),
              EventRule(name='EventRule 2', event_types=[OBJECT_CREATED], action_object=webhooks[1]),
              EventRule(name='EventRule 3', event_types=[OBJECT_CREATED], action_object=webhooks[2]),
          )
          EventRule.objects.bulk_create(event_rules)
  
          cls.create_data = [
              {
                  'name': 'EventRule 4',
                  'object_types': ['dcim.device', 'dcim.devicetype'],
                  'event_types': [OBJECT_CREATED],
                  'action_type': EventRuleActionChoices.WEBHOOK,
                  'action_object_type': 'extras.webhook',
                  'action_object_id': webhooks[3].pk,
              },
              {
                  'name': 'EventRule 5',
                  'object_types': ['dcim.device', 'dcim.devicetype'],
                  'event_types': [OBJECT_CREATED],
                  'action_type': EventRuleActionChoices.WEBHOOK,
                  'action_object_type': 'extras.webhook',
                  'action_object_id': webhooks[4].pk,
              },
              {
                  'name': 'EventRule 6',
                  'object_types': ['dcim.device', 'dcim.devicetype'],
                  'event_types': [OBJECT_CREATED],
                  'action_type': EventRuleActionChoices.WEBHOOK,
                  'action_object_type': 'extras.webhook',
                  'action_object_id': webhooks[5].pk,
              },
          ]
  
  
  class CustomFieldTest(APIViewTestCases.APIViewTestCase):
      model = CustomField
      brief_fields = ['description', 'display', 'id', 'name', 'url']
      create_data = [
          {
              'object_types': ['dcim.site'],
              'name': 'cf4',
              'type': 'date',
          },
          {
              'object_types': ['dcim.site'],
              'name': 'cf5',
              'type': 'url',
          },
          {
              'object_types': ['dcim.site'],
              'name': 'cf6',
              'type': 'text',
          },
      ]
      bulk_update_data = {
          'description': 'New description',
      }
      update_data = {
          'object_types': ['dcim.device'],
          'name': 'New_Name',
          'description': 'New description',
      }
  
      @classmethod
      def setUpTestData(cls):
          site_ct = ObjectType.objects.get_for_model(Site)
  
          custom_fields = (
              CustomField(
                  name='cf1',
                  type='text'
              ),
              CustomField(
                  name='cf2',
                  type='integer'
              ),
              CustomField(
                  name='cf3',
                  type='boolean'
              ),
          )
          CustomField.objects.bulk_create(custom_fields)
          for cf in custom_fields:
              cf.object_types.add(site_ct)
  
  
  class CustomFieldChoiceSetTest(APIViewTestCases.APIViewTestCase):
      model = CustomFieldChoiceSet
      brief_fields = ['choices_count', 'description', 'display', 'id', 'name', 'url']
      create_data = [
          {
              'name': 'Choice Set 4',
              'extra_choices': [
                  ['4A', 'Choice 1'],
                  ['4B', 'Choice 2'],
                  ['4C', 'Choice 3'],
              ],
          },
          {
              'name': 'Choice Set 5',
              'extra_choices': [
                  ['5A', 'Choice 1'],
                  ['5B', 'Choice 2'],
                  ['5C', 'Choice 3'],
              ],
          },
          {
              'name': 'Choice Set 6',
              'extra_choices': [
                  ['6A', 'Choice 1'],
                  ['6B', 'Choice 2'],
                  ['6C', 'Choice 3'],
              ],
          },
      ]
      bulk_update_data = {
          'description': 'New description',
      }
      update_data = {
          'name': 'Choice Set X',
          'extra_choices': [
              ['X1', 'Choice 1'],
              ['X2', 'Choice 2'],
              ['X3', 'Choice 3'],
          ],
          'description': 'New description',
      }
  
      @classmethod
      def setUpTestData(cls):
          choice_sets = (
              CustomFieldChoiceSet(
                  name='Choice Set 1',
                  extra_choices=[['1A', '1A'], ['1B', '1B'], ['1C', '1C'], ['1D', '1D'], ['1E', '1E']],
              ),
              CustomFieldChoiceSet(
                  name='Choice Set 2',
                  extra_choices=[['2A', '2A'], ['2B', '2B'], ['2C', '2C'], ['2D', '2D'], ['2E', '2E']],
              ),
              CustomFieldChoiceSet(
                  name='Choice Set 3',
                  extra_choices=[['3A', '3A'], ['3B', '3B'], ['3C', '3C'], ['3D', '3D'], ['3E', '3E']],
              ),
          )
          CustomFieldChoiceSet.objects.bulk_create(choice_sets)
  
      def test_invalid_choice_items(self):
          """
          Attempting to define each choice as a single-item list should return a 400 error.
          """
          self.add_permissions('extras.add_customfieldchoiceset')
          data = {
              "name": "test",
              "extra_choices": [
                  ["choice1"],
                  ["choice2"],
                  ["choice3"],
              ]
          }
  
          response = self.client.post(self._get_list_url(), data, format='json', **self.header)
          self.assertEqual(response.status_code, 400)
  
  
  class CustomLinkTest(APIViewTestCases.APIViewTestCase):
      model = CustomLink
      brief_fields = ['display', 'id', 'name', 'url']
      create_data = [
          {
              'object_types': ['dcim.site'],
              'name': 'Custom Link 4',
              'enabled': True,
              'link_text': 'Link 4',
              'link_url': 'http://example.com/?4',
          },
          {
              'object_types': ['dcim.site'],
              'name': 'Custom Link 5',
              'enabled': True,
              'link_text': 'Link 5',
              'link_url': 'http://example.com/?5',
          },
          {
              'object_types': ['dcim.site'],
              'name': 'Custom Link 6',
              'enabled': False,
              'link_text': 'Link 6',
              'link_url': 'http://example.com/?6',
          },
      ]
      bulk_update_data = {
          'new_window': True,
          'enabled': False,
      }
  
      @classmethod
      def setUpTestData(cls):
          site_type = ObjectType.objects.get_for_model(Site)
  
          custom_links = (
              CustomLink(
                  name='Custom Link 1',
                  enabled=True,
                  link_text='Link 1',
                  link_url='http://example.com/?1',
              ),
              CustomLink(
                  name='Custom Link 2',
                  enabled=True,
                  link_text='Link 2',
                  link_url='http://example.com/?2',
              ),
              CustomLink(
                  name='Custom Link 3',
                  enabled=False,
                  link_text='Link 3',
                  link_url='http://example.com/?3',
              ),
          )
          CustomLink.objects.bulk_create(custom_links)
          for i, custom_link in enumerate(custom_links):
              custom_link.object_types.set([site_type])
  
  
  class SavedFilterTest(APIViewTestCases.APIViewTestCase):
      model = SavedFilter
      brief_fields = ['description', 'display', 'id', 'name', 'slug', 'url']
      create_data = [
          {
              'object_types': ['dcim.site'],
              'name': 'Saved Filter 4',
              'slug': 'saved-filter-4',
              'weight': 100,
              'enabled': True,
              'shared': True,
              'parameters': {'status': ['active']},
          },
          {
              'object_types': ['dcim.site'],
              'name': 'Saved Filter 5',
              'slug': 'saved-filter-5',
              'weight': 200,
              'enabled': True,
              'shared': True,
              'parameters': {'status': ['planned']},
          },
          {
              'object_types': ['dcim.site'],
              'name': 'Saved Filter 6',
              'slug': 'saved-filter-6',
              'weight': 300,
              'enabled': True,
              'shared': True,
              'parameters': {'status': ['retired']},
          },
      ]
      bulk_update_data = {
          'weight': 1000,
          'enabled': False,
          'shared': False,
      }
  
      @classmethod
      def setUpTestData(cls):
          site_type = ObjectType.objects.get_for_model(Site)
  
          saved_filters = (
              SavedFilter(
                  name='Saved Filter 1',
                  slug='saved-filter-1',
                  weight=100,
                  enabled=True,
                  shared=True,
                  parameters={'status': ['active']}
              ),
              SavedFilter(
                  name='Saved Filter 2',
                  slug='saved-filter-2',
                  weight=200,
                  enabled=True,
                  shared=True,
                  parameters={'status': ['planned']}
              ),
              SavedFilter(
                  name='Saved Filter 3',
                  slug='saved-filter-3',
                  weight=300,
                  enabled=True,
                  shared=True,
                  parameters={'status': ['retired']}
              ),
          )
          SavedFilter.objects.bulk_create(saved_filters)
          for i, savedfilter in enumerate(saved_filters):
              savedfilter.object_types.set([site_type])
  
  
  class BookmarkTest(
      APIViewTestCases.GetObjectViewTestCase,
      APIViewTestCases.ListObjectsViewTestCase,
      APIViewTestCases.CreateObjectViewTestCase,
      APIViewTestCases.DeleteObjectViewTestCase
  ):
      model = Bookmark
      brief_fields = ['display', 'id', 'object_id', 'object_type', 'url']
  
      @classmethod
      def setUpTestData(cls):
          sites = (
              Site(name='Site 1', slug='site-1'),
              Site(name='Site 2', slug='site-2'),
              Site(name='Site 3', slug='site-3'),
              Site(name='Site 4', slug='site-4'),
              Site(name='Site 5', slug='site-5'),
              Site(name='Site 6', slug='site-6'),
          )
          Site.objects.bulk_create(sites)
  
      def setUp(self):
          super().setUp()
  
          sites = Site.objects.all()
  
          bookmarks = (
              Bookmark(object=sites[0], user=self.user),
              Bookmark(object=sites[1], user=self.user),
              Bookmark(object=sites[2], user=self.user),
          )
          Bookmark.objects.bulk_create(bookmarks)
  
          self.create_data = [
              {
                  'object_type': 'dcim.site',
                  'object_id': sites[3].pk,
                  'user': self.user.pk,
              },
              {
                  'object_type': 'dcim.site',
                  'object_id': sites[4].pk,
                  'user': self.user.pk,
              },
              {
                  'object_type': 'dcim.site',
                  'object_id': sites[5].pk,
                  'user': self.user.pk,
              },
          ]
  
  
  class ExportTemplateTest(APIViewTestCases.APIViewTestCase):
      model = ExportTemplate
      brief_fields = ['description', 'display', 'id', 'name', 'url']
      create_data = [
          {
              'object_types': ['dcim.device'],
              'name': 'Test Export Template 4',
              'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
          },
          {
              'object_types': ['dcim.device'],
              'name': 'Test Export Template 5',
              'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
          },
          {
              'object_types': ['dcim.device'],
              'name': 'Test Export Template 6',
              'template_code': '{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
              'file_name': 'test_export_template_6',
          },
      ]
      bulk_update_data = {
          'description': 'New description',
      }
  
      @classmethod
      def setUpTestData(cls):
          export_templates = (
              ExportTemplate(
                  name='Export Template 1',
                  template_code='{% for obj in queryset %}{{ obj.name }}\n{% endfor %}'
              ),
              ExportTemplate(
                  name='Export Template 2',
                  template_code='{% for obj in queryset %}{{ obj.name }}\n{% endfor %}',
                  file_name='export_template_2',
                  file_extension='test',
              ),
              ExportTemplate(
                  name='Export Template 3',
                  template_code='{% for obj in queryset %}{{ obj.name }}\n{% endfor %}'
              ),
          )
          ExportTemplate.objects.bulk_create(export_templates)
  
          device_object_type = ObjectType.objects.get_for_model(Device)
          for et in export_templates:
              et.object_types.set([device_object_type])
  
  
  class TagTest(APIViewTestCases.APIViewTestCase):
      model = Tag
      brief_fields = ['color', 'description', 'display', 'id', 'name', 'slug', 'url']
      create_data = [
          {
              'name': 'Tag 4',
              'slug': 'tag-4',
              'weight': 1000,
          },
          {
              'name': 'Tag 5',
              'slug': 'tag-5',
          },
          {
              'name': 'Tag 6',
              'slug': 'tag-6',
          },
      ]
      bulk_update_data = {
          'description': 'New description',
      }
  
      @classmethod
      def setUpTestData(cls):
  
          tags = (
              Tag(name='Tag 1', slug='tag-1'),
              Tag(name='Tag 2', slug='tag-2'),
              Tag(name='Tag 3', slug='tag-3', weight=26),
          )
          Tag.objects.bulk_create(tags)
  
  
  class TaggedItemTest(
      APIViewTestCases.GetObjectViewTestCase,
      APIViewTestCases.ListObjectsViewTestCase
  ):
      model = TaggedItem
      brief_fields = ['display', 'id', 'object', 'object_id', 'object_type', 'tag', 'url']
  
      @classmethod
      def setUpTestData(cls):
  
          tags = (
              Tag(name='Tag 1', slug='tag-1'),
              Tag(name='Tag 2', slug='tag-2'),
              Tag(name='Tag 3', slug='tag-3'),
          )
          Tag.objects.bulk_create(tags)
  
          sites = (
              Site(name='Site 1', slug='site-1'),
              Site(name='Site 2', slug='site-2'),
              Site(name='Site 3', slug='site-3'),
          )
          Site.objects.bulk_create(sites)
          sites[0].tags.set([tags[0], tags[1]])
          sites[1].tags.set([tags[1], tags[2]])
          sites[2].tags.set([tags[2], tags[0]])
  
  
  # TODO: Standardize to APIViewTestCase (needs create & update tests)
  class ImageAttachmentTest(
      APIViewTestCases.GetObjectViewTestCase,
      APIViewTestCases.ListObjectsViewTestCase,
      APIViewTestCases.DeleteObjectViewTestCase,
      APIViewTestCases.GraphQLTestCase
  ):
      model = ImageAttachment
      brief_fields = ['description', 'display', 'id', 'image', 'name', 'url']
  
      @classmethod
      def setUpTestData(cls):
          ct = ContentType.objects.get_for_model(Site)
  
          site = Site.objects.create(name='Site 1', slug='site-1')
  
          image_attachments = (
              ImageAttachment(
                  object_type=ct,
                  object_id=site.pk,
                  name='Image Attachment 1',
                  image='http://example.com/image1.png',
                  image_height=100,
                  image_width=100
              ),
              ImageAttachment(
                  object_type=ct,
                  object_id=site.pk,
                  name='Image Attachment 2',
                  image='http://example.com/image2.png',
                  image_height=100,
                  image_width=100
              ),
              ImageAttachment(
                  object_type=ct,
                  object_id=site.pk,
                  name='Image Attachment 3',
                  image='http://example.com/image3.png',
                  image_height=100,
                  image_width=100
              )
          )
          ImageAttachment.objects.bulk_create(image_attachments)
  
  
  class JournalEntryTest(APIViewTestCases.APIViewTestCase):
      model = JournalEntry
      brief_fields = ['created', 'display', 'id', 'url']
      bulk_update_data = {
          'comments': 'Overwritten',
      }
  
      @classmethod
      def setUpTestData(cls):
          user = User.objects.first()
          site = Site.objects.create(name='Site 1', slug='site-1')
  
          journal_entries = (
              JournalEntry(
                  created_by=user,
                  assigned_object=site,
                  comments='Fourth entry',
              ),
              JournalEntry(
                  created_by=user,
                  assigned_object=site,
                  comments='Fifth entry',
              ),
              JournalEntry(
                  created_by=user,
                  assigned_object=site,
                  comments='Sixth entry',
              ),
          )
          JournalEntry.objects.bulk_create(journal_entries)
  
          cls.create_data = [
              {
                  'assigned_object_type': 'dcim.site',
                  'assigned_object_id': site.pk,
                  'comments': 'First entry',
              },
              {
                  'assigned_object_type': 'dcim.site',
                  'assigned_object_id': site.pk,
                  'comments': 'Second entry',
              },
              {
                  'assigned_object_type': 'dcim.site',
                  'assigned_object_id': site.pk,
                  'comments': 'Third entry',
              },
          ]
  
  
  class ConfigContextProfileTest(APIViewTestCases.APIViewTestCase):
      model = ConfigContextProfile
      brief_fields = ['description', 'display', 'id', 'name', 'url']
      create_data = [
          {
              'name': 'Config Context Profile 4',
          },
          {
              'name': 'Config Context Profile 5',
          },
          {
              'name': 'Config Context Profile 6',
          },
      ]
      bulk_update_data = {
          'description': 'New description',
      }
  
      @classmethod
      def setUpTestData(cls):
          profiles = (
              ConfigContextProfile(
                  name='Config Context Profile 1',
                  schema={
                      "properties": {
                          "foo": {
                              "type": "string"
                          }
                      },
                      "required": [
                          "foo"
                      ]
                  }
              ),
              ConfigContextProfile(
                  name='Config Context Profile 2',
                  schema={
                      "properties": {
                          "bar": {
                              "type": "string"
                          }
                      },
                      "required": [
                          "bar"
                      ]
                  }
              ),
              ConfigContextProfile(
                  name='Config Context Profile 3',
                  schema={
                      "properties": {
                          "baz": {
                              "type": "string"
                          }
                      },
                      "required": [
                          "baz"
                      ]
                  }
              ),
          )
          ConfigContextProfile.objects.bulk_create(profiles)
  
  
  class ConfigContextTest(APIViewTestCases.APIViewTestCase):
      model = ConfigContext
      brief_fields = ['description', 'display', 'id', 'name', 'url']
      create_data = [
          {
              'name': 'Config Context 4',
              'data': {'more_foo': True},
          },
          {
              'name': 'Config Context 5',
              'data': {'more_bar': False},
          },
          {
              'name': 'Config Context 6',
              'data': {'more_baz': None},
          },
      ]
      bulk_update_data = {
          'description': 'New description',
      }
  
      @classmethod
      def setUpTestData(cls):
  
          config_contexts = (
              ConfigContext(name='Config Context 1', weight=100, data={'foo': 123}),
              ConfigContext(name='Config Context 2', weight=200, data={'bar': 456}),
              ConfigContext(name='Config Context 3', weight=300, data={'baz': 789}),
          )
          ConfigContext.objects.bulk_create(config_contexts)
  
      def test_render_configcontext_for_object(self):
          """
          Test rendering config context data for a device.
          """
          manufacturer = Manufacturer.objects.create(name='Manufacturer 1', slug='manufacturer-1')
          devicetype = DeviceType.objects.create(manufacturer=manufacturer, model='Device Type 1', slug='device-type-1')
          role = DeviceRole.objects.create(name='Device Role 1', slug='device-role-1')
          site = Site.objects.create(name='Site-1', slug='site-1')
          device = Device.objects.create(name='Device 1', device_type=devicetype, role=role, site=site)
  
          # Test default config contexts (created at test setup)
          rendered_context = device.get_config_context()
          self.assertEqual(rendered_context['foo'], 123)
          self.assertEqual(rendered_context['bar'], 456)
          self.assertEqual(rendered_context['baz'], 789)
  
          # Add another context specific to the site
          configcontext4 = ConfigContext(
              name='Config Context 4',
              data={'site_data': 'ABC'}
          )
          configcontext4.save()
          configcontext4.sites.add(site)
          rendered_context = device.get_config_context()
          self.assertEqual(rendered_context['site_data'], 'ABC')
  
          # Override one of the default contexts
          configcontext5 = ConfigContext(
              name='Config Context 5',
              weight=2000,
              data={'foo': 999}
          )
          configcontext5.save()
          configcontext5.sites.add(site)
          rendered_context = device.get_config_context()
          self.assertEqual(rendered_context['foo'], 999)
  
          # Add a context which does NOT match our device and ensure it does not apply
          site2 = Site.objects.create(name='Site 2', slug='site-2')
          configcontext6 = ConfigContext(
              name='Config Context 6',
              weight=2000,
              data={'bar': 999}
          )
          configcontext6.save()
          configcontext6.sites.add(site2)
          rendered_context = device.get_config_context()
          self.assertEqual(rendered_context['bar'], 456)
  
  
  class ConfigTemplateTest(APIViewTestCases.APIViewTestCase):
      model = ConfigTemplate
      brief_fields = ['description', 'display', 'id', 'name', 'url']
      create_data = [
          {
              'name': 'Config Template 4',
              'template_code': 'Foo: {{ foo }}',
              'mime_type': 'text/plain',
              'file_name': 'output4',
              'file_extension': 'txt',
              'as_attachment': True,
          },
          {
              'name': 'Config Template 5',
              'template_code': 'Bar: {{ bar }}',
          },
          {
              'name': 'Config Template 6',
              'template_code': 'Baz: {{ baz }}',
          },
      ]
      bulk_update_data = {
          'description': 'New description',
      }
  
      @classmethod
      def setUpTestData(cls):
          config_templates = (
              ConfigTemplate(
                  name='Config Template 1',
                  template_code='Foo: {{ foo }}'
              ),
              ConfigTemplate(
                  name='Config Template 2',
                  template_code='Bar: {{ bar }}',
              ),
              ConfigTemplate(
                  name='Config Template 3',
                  template_code='Baz: {{ baz }}'
              ),
          )
          ConfigTemplate.objects.bulk_create(config_templates)
  
  
  class ScriptTest(APITestCase):
  
      class TestScriptClass(PythonClass):
          class Meta:
              name = 'Test script'
              commit = True
              scheduling_enabled = True
  
          var1 = StringVar()
          var2 = IntegerVar()
          var3 = BooleanVar()
  
          def run(self, data, commit=True):
              self.log_info(data['var1'])
              self.log_success(data['var2'])
              self.log_failure(data['var3'])
  
              return 'Script complete'
  
      @classmethod
      def setUpTestData(cls):
          module = ScriptModule.objects.create(
              file_root=ManagedFileRootPathChoices.SCRIPTS,
              file_path='script.py',
          )
          script = Script.objects.create(
              module=module,
              name='Test script',
              is_executable=True,
          )
          cls.url = reverse('extras-api:script-detail', kwargs={'pk': script.pk})
  
      @property
      def python_class(self):
          return self.TestScriptClass
  
      def setUp(self):
          super().setUp()
          self.add_permissions('extras.view_script')
  
          # Monkey-patch the Script model to return our TestScriptClass above
          Script.python_class = self.python_class
  
      def test_get_script(self):
          response = self.client.get(self.url, **self.header)
  
          self.assertEqual(response.data['name'], self.TestScriptClass.Meta.name)
          self.assertEqual(response.data['vars']['var1'], 'StringVar')
          self.assertEqual(response.data['vars']['var2'], 'IntegerVar')
          self.assertEqual(response.data['vars']['var3'], 'BooleanVar')
  
      def test_schedule_script_past_time_rejected(self):
          """
          Scheduling with past schedule_at should fail.
          """
          self.add_permissions('extras.run_script')
  
          payload = {
              'data': {'var1': 'hello', 'var2': 1, 'var3': False},
              'commit': True,
              'schedule_at': now() - datetime.timedelta(hours=1),
          }
          response = self.client.post(self.url, payload, format='json', **self.header)
  
          self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
          self.assertIn('schedule_at', response.data)
          # Be tolerant of exact wording but ensure we failed on schedule_at being in the past
          self.assertIn('future', str(response.data['schedule_at']).lower())
  
      def test_schedule_script_interval_only(self):
          """
          Interval without schedule_at should auto-set schedule_at now.
          """
          self.add_permissions('extras.run_script')
  
          payload = {
              'data': {'var1': 'hello', 'var2': 1, 'var3': False},
              'commit': True,
              'interval': 60,
          }
          response = self.client.post(self.url, payload, format='json', **self.header)
  
          self.assertHttpStatus(response, status.HTTP_200_OK)
          # The latest job is returned in the script detail serializer under "result"
          self.assertIn('result', response.data)
          self.assertEqual(response.data['result']['interval'], 60)
          # Ensure a start time was autopopulated
          self.assertIsNotNone(response.data['result']['scheduled'])
  
      def test_schedule_script_when_disabled(self):
          """
          Scheduling should fail when script.scheduling_enabled=False.
          """
          self.add_permissions('extras.run_script')
  
          # Temporarily disable scheduling on the in-test Python class
          original = getattr(self.TestScriptClass.Meta, 'scheduling_enabled', True)
          self.TestScriptClass.Meta.scheduling_enabled = False
          base = {
              'data': {'var1': 'hello', 'var2': 1, 'var3': False},
              'commit': True,
          }
          # Check both schedule_at and interval paths
          cases = [
              {**base, 'schedule_at': now() + datetime.timedelta(minutes=5)},
              {**base, 'interval': 60},
          ]
          try:
              for case in cases:
                  with self.subTest(case=list(case.keys())):
                      response = self.client.post(self.url, case, format='json', **self.header)
  
                      self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
                      # Error should be attached to whichever field we used
                      key = 'schedule_at' if 'schedule_at' in case else 'interval'
                      self.assertIn(key, response.data)
                      self.assertIn('scheduling is not enabled', str(response.data[key]).lower())
          finally:
              # Restore the original setting for other tests
              self.TestScriptClass.Meta.scheduling_enabled = original
  
  
  class CreatedUpdatedFilterTest(APITestCase):
  
      @classmethod
      def setUpTestData(cls):
          site1 = Site.objects.create(name='Site 1', slug='site-1')
          location1 = Location.objects.create(site=site1, name='Location 1', slug='location-1')
          rackrole1 = RackRole.objects.create(name='Rack Role 1', slug='rack-role-1', color='ff0000')
          racks = (
              Rack(site=site1, location=location1, role=rackrole1, name='Rack 1', u_height=42),
              Rack(site=site1, location=location1, role=rackrole1, name='Rack 2', u_height=42)
          )
          Rack.objects.bulk_create(racks)
  
          # Change the created and last_updated of the second rack
          Rack.objects.filter(pk=racks[1].pk).update(
              last_updated=make_aware(datetime.datetime(2001, 2, 3, 1, 2, 3, 4)),
              created=make_aware(datetime.datetime(2001, 2, 3))
          )
  
      def test_get_rack_created(self):
          rack2 = Rack.objects.get(name='Rack 2')
          self.add_permissions('dcim.view_rack')
          url = reverse('dcim-api:rack-list')
          response = self.client.get('{}?created=2001-02-03'.format(url), **self.header)
  
          self.assertEqual(response.data['count'], 1)
          self.assertEqual(response.data['results'][0]['id'], rack2.pk)
  
      def test_get_rack_created_gte(self):
          rack1 = Rack.objects.get(name='Rack 1')
          self.add_permissions('dcim.view_rack')
          url = reverse('dcim-api:rack-list')
          response = self.client.get('{}?created__gte=2001-02-04'.format(url), **self.header)
  
          self.assertEqual(response.data['count'], 1)
          self.assertEqual(response.data['results'][0]['id'], rack1.pk)
  
      def test_get_rack_created_lte(self):
          rack2 = Rack.objects.get(name='Rack 2')
          self.add_permissions('dcim.view_rack')
          url = reverse('dcim-api:rack-list')
  