mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
14132 Add EventRule - change webhook and add in script processing to events (#14267)
--------- Co-authored-by: Jeremy Stretch <jstretch@netboxlabs.com>
This commit is contained in:
@@ -8,6 +8,7 @@ from rest_framework import status
|
||||
|
||||
from core.choices import ManagedFileRootPathChoices
|
||||
from dcim.models import Device, DeviceRole, DeviceType, Manufacturer, Rack, Location, RackRole, Site
|
||||
from extras.choices import *
|
||||
from extras.models import *
|
||||
from extras.reports import Report
|
||||
from extras.scripts import BooleanVar, IntegerVar, Script, StringVar
|
||||
@@ -32,21 +33,15 @@ class WebhookTest(APIViewTestCases.APIViewTestCase):
|
||||
brief_fields = ['display', 'id', 'name', 'url']
|
||||
create_data = [
|
||||
{
|
||||
'content_types': ['dcim.device', 'dcim.devicetype'],
|
||||
'name': 'Webhook 4',
|
||||
'type_create': True,
|
||||
'payload_url': 'http://example.com/?4',
|
||||
},
|
||||
{
|
||||
'content_types': ['dcim.device', 'dcim.devicetype'],
|
||||
'name': 'Webhook 5',
|
||||
'type_update': True,
|
||||
'payload_url': 'http://example.com/?5',
|
||||
},
|
||||
{
|
||||
'content_types': ['dcim.device', 'dcim.devicetype'],
|
||||
'name': 'Webhook 6',
|
||||
'type_delete': True,
|
||||
'payload_url': 'http://example.com/?6',
|
||||
},
|
||||
]
|
||||
@@ -56,29 +51,100 @@ class WebhookTest(APIViewTestCases.APIViewTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
site_ct = ContentType.objects.get_for_model(Site)
|
||||
rack_ct = ContentType.objects.get_for_model(Rack)
|
||||
|
||||
webhooks = (
|
||||
Webhook(
|
||||
name='Webhook 1',
|
||||
type_create=True,
|
||||
payload_url='http://example.com/?1',
|
||||
),
|
||||
Webhook(
|
||||
name='Webhook 2',
|
||||
type_update=True,
|
||||
payload_url='http://example.com/?1',
|
||||
),
|
||||
Webhook(
|
||||
name='Webhook 3',
|
||||
type_delete=True,
|
||||
payload_url='http://example.com/?1',
|
||||
),
|
||||
)
|
||||
Webhook.objects.bulk_create(webhooks)
|
||||
for webhook in webhooks:
|
||||
webhook.content_types.add(site_ct, rack_ct)
|
||||
|
||||
|
||||
class EventRuleTest(APIViewTestCases.APIViewTestCase):
|
||||
model = EventRule
|
||||
brief_fields = ['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', type_create=True, action_object=webhooks[0]),
|
||||
EventRule(name='EventRule 2', type_create=True, action_object=webhooks[1]),
|
||||
EventRule(name='EventRule 3', type_create=True, action_object=webhooks[2]),
|
||||
)
|
||||
EventRule.objects.bulk_create(event_rules)
|
||||
|
||||
cls.create_data = [
|
||||
{
|
||||
'name': 'EventRule 4',
|
||||
'content_types': ['dcim.device', 'dcim.devicetype'],
|
||||
'type_create': True,
|
||||
'action_type': EventRuleActionChoices.WEBHOOK,
|
||||
'action_object_type': 'extras.webhook',
|
||||
'action_object_id': webhooks[3].pk,
|
||||
},
|
||||
{
|
||||
'name': 'EventRule 5',
|
||||
'content_types': ['dcim.device', 'dcim.devicetype'],
|
||||
'type_create': True,
|
||||
'action_type': EventRuleActionChoices.WEBHOOK,
|
||||
'action_object_type': 'extras.webhook',
|
||||
'action_object_id': webhooks[4].pk,
|
||||
},
|
||||
{
|
||||
'name': 'EventRule 6',
|
||||
'content_types': ['dcim.device', 'dcim.devicetype'],
|
||||
'type_create': True,
|
||||
'action_type': EventRuleActionChoices.WEBHOOK,
|
||||
'action_object_type': 'extras.webhook',
|
||||
'action_object_id': webhooks[5].pk,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class CustomFieldTest(APIViewTestCases.APIViewTestCase):
|
||||
|
||||
@@ -3,22 +3,22 @@ import uuid
|
||||
from unittest.mock import patch
|
||||
|
||||
import django_rq
|
||||
from dcim.choices import SiteStatusChoices
|
||||
from dcim.models import Site
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.http import HttpResponse
|
||||
from django.urls import reverse
|
||||
from extras.choices import EventRuleActionChoices, ObjectChangeActionChoices
|
||||
from extras.events import enqueue_object, flush_events, serialize_for_event
|
||||
from extras.models import EventRule, Tag, Webhook
|
||||
from extras.webhooks import generate_signature
|
||||
from extras.webhooks_worker import process_webhook
|
||||
from requests import Session
|
||||
from rest_framework import status
|
||||
|
||||
from dcim.choices import SiteStatusChoices
|
||||
from dcim.models import Site
|
||||
from extras.choices import ObjectChangeActionChoices
|
||||
from extras.models import Tag, Webhook
|
||||
from extras.webhooks import enqueue_object, flush_webhooks, generate_signature, serialize_for_webhook
|
||||
from extras.webhooks_worker import eval_conditions, process_webhook
|
||||
from utilities.testing import APITestCase
|
||||
|
||||
|
||||
class WebhookTest(APITestCase):
|
||||
class EventRuleTest(APITestCase):
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
@@ -35,12 +35,37 @@ class WebhookTest(APITestCase):
|
||||
DUMMY_SECRET = 'LOOKATMEIMASECRETSTRING'
|
||||
|
||||
webhooks = Webhook.objects.bulk_create((
|
||||
Webhook(name='Webhook 1', type_create=True, payload_url=DUMMY_URL, secret=DUMMY_SECRET, additional_headers='X-Foo: Bar'),
|
||||
Webhook(name='Webhook 2', type_update=True, payload_url=DUMMY_URL, secret=DUMMY_SECRET),
|
||||
Webhook(name='Webhook 3', type_delete=True, payload_url=DUMMY_URL, secret=DUMMY_SECRET),
|
||||
Webhook(name='Webhook 1', payload_url=DUMMY_URL, secret=DUMMY_SECRET, additional_headers='X-Foo: Bar'),
|
||||
Webhook(name='Webhook 2', payload_url=DUMMY_URL, secret=DUMMY_SECRET),
|
||||
Webhook(name='Webhook 3', payload_url=DUMMY_URL, secret=DUMMY_SECRET),
|
||||
))
|
||||
for webhook in webhooks:
|
||||
webhook.content_types.set([site_ct])
|
||||
|
||||
ct = ContentType.objects.get(app_label='extras', model='webhook')
|
||||
event_rules = EventRule.objects.bulk_create((
|
||||
EventRule(
|
||||
name='Webhook Event 1',
|
||||
type_create=True,
|
||||
action_type=EventRuleActionChoices.WEBHOOK,
|
||||
action_object_type=ct,
|
||||
action_object_id=webhooks[0].id
|
||||
),
|
||||
EventRule(
|
||||
name='Webhook Event 2',
|
||||
type_update=True,
|
||||
action_type=EventRuleActionChoices.WEBHOOK,
|
||||
action_object_type=ct,
|
||||
action_object_id=webhooks[0].id
|
||||
),
|
||||
EventRule(
|
||||
name='Webhook Event 3',
|
||||
type_delete=True,
|
||||
action_type=EventRuleActionChoices.WEBHOOK,
|
||||
action_object_type=ct,
|
||||
action_object_id=webhooks[0].id
|
||||
),
|
||||
))
|
||||
for event_rule in event_rules:
|
||||
event_rule.content_types.set([site_ct])
|
||||
|
||||
Tag.objects.bulk_create((
|
||||
Tag(name='Foo', slug='foo'),
|
||||
@@ -48,7 +73,42 @@ class WebhookTest(APITestCase):
|
||||
Tag(name='Baz', slug='baz'),
|
||||
))
|
||||
|
||||
def test_enqueue_webhook_create(self):
|
||||
def test_eventrule_conditions(self):
|
||||
"""
|
||||
Test evaluation of EventRule conditions.
|
||||
"""
|
||||
event_rule = EventRule(
|
||||
name='Event Rule 1',
|
||||
type_create=True,
|
||||
type_update=True,
|
||||
conditions={
|
||||
'and': [
|
||||
{
|
||||
'attr': 'status.value',
|
||||
'value': 'active',
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
# Create a Site to evaluate
|
||||
site = Site.objects.create(name='Site 1', slug='site-1', status=SiteStatusChoices.STATUS_STAGING)
|
||||
data = serialize_for_event(site)
|
||||
|
||||
# Evaluate the conditions (status='staging')
|
||||
self.assertFalse(event_rule.eval_conditions(data))
|
||||
|
||||
# Change the site's status
|
||||
site.status = SiteStatusChoices.STATUS_ACTIVE
|
||||
data = serialize_for_event(site)
|
||||
|
||||
# Evaluate the conditions (status='active')
|
||||
self.assertTrue(event_rule.eval_conditions(data))
|
||||
|
||||
def test_single_create_process_eventrule(self):
|
||||
"""
|
||||
Check that creating an object with an applicable EventRule queues a background task for the rule's action.
|
||||
"""
|
||||
# Create an object via the REST API
|
||||
data = {
|
||||
'name': 'Site 1',
|
||||
@@ -65,10 +125,10 @@ class WebhookTest(APITestCase):
|
||||
self.assertEqual(Site.objects.count(), 1)
|
||||
self.assertEqual(Site.objects.first().tags.count(), 2)
|
||||
|
||||
# Verify that a job was queued for the object creation webhook
|
||||
# Verify that a background task was queued for the new object
|
||||
self.assertEqual(self.queue.count, 1)
|
||||
job = self.queue.jobs[0]
|
||||
self.assertEqual(job.kwargs['webhook'], Webhook.objects.get(type_create=True))
|
||||
self.assertEqual(job.kwargs['event_rule'], EventRule.objects.get(type_create=True))
|
||||
self.assertEqual(job.kwargs['event'], ObjectChangeActionChoices.ACTION_CREATE)
|
||||
self.assertEqual(job.kwargs['model_name'], 'site')
|
||||
self.assertEqual(job.kwargs['data']['id'], response.data['id'])
|
||||
@@ -76,7 +136,11 @@ class WebhookTest(APITestCase):
|
||||
self.assertEqual(job.kwargs['snapshots']['postchange']['name'], 'Site 1')
|
||||
self.assertEqual(job.kwargs['snapshots']['postchange']['tags'], ['Bar', 'Foo'])
|
||||
|
||||
def test_enqueue_webhook_bulk_create(self):
|
||||
def test_bulk_create_process_eventrule(self):
|
||||
"""
|
||||
Check that bulk creating multiple objects with an applicable EventRule queues a background task for each
|
||||
new object.
|
||||
"""
|
||||
# Create multiple objects via the REST API
|
||||
data = [
|
||||
{
|
||||
@@ -111,10 +175,10 @@ class WebhookTest(APITestCase):
|
||||
self.assertEqual(Site.objects.count(), 3)
|
||||
self.assertEqual(Site.objects.first().tags.count(), 2)
|
||||
|
||||
# Verify that a webhook was queued for each object
|
||||
# Verify that a background task was queued for each new object
|
||||
self.assertEqual(self.queue.count, 3)
|
||||
for i, job in enumerate(self.queue.jobs):
|
||||
self.assertEqual(job.kwargs['webhook'], Webhook.objects.get(type_create=True))
|
||||
self.assertEqual(job.kwargs['event_rule'], EventRule.objects.get(type_create=True))
|
||||
self.assertEqual(job.kwargs['event'], ObjectChangeActionChoices.ACTION_CREATE)
|
||||
self.assertEqual(job.kwargs['model_name'], 'site')
|
||||
self.assertEqual(job.kwargs['data']['id'], response.data[i]['id'])
|
||||
@@ -122,7 +186,10 @@ class WebhookTest(APITestCase):
|
||||
self.assertEqual(job.kwargs['snapshots']['postchange']['name'], response.data[i]['name'])
|
||||
self.assertEqual(job.kwargs['snapshots']['postchange']['tags'], ['Bar', 'Foo'])
|
||||
|
||||
def test_enqueue_webhook_update(self):
|
||||
def test_single_update_process_eventrule(self):
|
||||
"""
|
||||
Check that updating an object with an applicable EventRule queues a background task for the rule's action.
|
||||
"""
|
||||
site = Site.objects.create(name='Site 1', slug='site-1')
|
||||
site.tags.set(Tag.objects.filter(name__in=['Foo', 'Bar']))
|
||||
|
||||
@@ -139,10 +206,10 @@ class WebhookTest(APITestCase):
|
||||
response = self.client.patch(url, data, format='json', **self.header)
|
||||
self.assertHttpStatus(response, status.HTTP_200_OK)
|
||||
|
||||
# Verify that a job was queued for the object update webhook
|
||||
# Verify that a background task was queued for the updated object
|
||||
self.assertEqual(self.queue.count, 1)
|
||||
job = self.queue.jobs[0]
|
||||
self.assertEqual(job.kwargs['webhook'], Webhook.objects.get(type_update=True))
|
||||
self.assertEqual(job.kwargs['event_rule'], EventRule.objects.get(type_update=True))
|
||||
self.assertEqual(job.kwargs['event'], ObjectChangeActionChoices.ACTION_UPDATE)
|
||||
self.assertEqual(job.kwargs['model_name'], 'site')
|
||||
self.assertEqual(job.kwargs['data']['id'], site.pk)
|
||||
@@ -152,7 +219,11 @@ class WebhookTest(APITestCase):
|
||||
self.assertEqual(job.kwargs['snapshots']['postchange']['name'], 'Site X')
|
||||
self.assertEqual(job.kwargs['snapshots']['postchange']['tags'], ['Baz'])
|
||||
|
||||
def test_enqueue_webhook_bulk_update(self):
|
||||
def test_bulk_update_process_eventrule(self):
|
||||
"""
|
||||
Check that bulk updating multiple objects with an applicable EventRule queues a background task for each
|
||||
updated object.
|
||||
"""
|
||||
sites = (
|
||||
Site(name='Site 1', slug='site-1'),
|
||||
Site(name='Site 2', slug='site-2'),
|
||||
@@ -191,10 +262,10 @@ class WebhookTest(APITestCase):
|
||||
response = self.client.patch(url, data, format='json', **self.header)
|
||||
self.assertHttpStatus(response, status.HTTP_200_OK)
|
||||
|
||||
# Verify that a job was queued for the object update webhook
|
||||
# Verify that a background task was queued for each updated object
|
||||
self.assertEqual(self.queue.count, 3)
|
||||
for i, job in enumerate(self.queue.jobs):
|
||||
self.assertEqual(job.kwargs['webhook'], Webhook.objects.get(type_update=True))
|
||||
self.assertEqual(job.kwargs['event_rule'], EventRule.objects.get(type_update=True))
|
||||
self.assertEqual(job.kwargs['event'], ObjectChangeActionChoices.ACTION_UPDATE)
|
||||
self.assertEqual(job.kwargs['model_name'], 'site')
|
||||
self.assertEqual(job.kwargs['data']['id'], data[i]['id'])
|
||||
@@ -204,7 +275,10 @@ class WebhookTest(APITestCase):
|
||||
self.assertEqual(job.kwargs['snapshots']['postchange']['name'], response.data[i]['name'])
|
||||
self.assertEqual(job.kwargs['snapshots']['postchange']['tags'], ['Baz'])
|
||||
|
||||
def test_enqueue_webhook_delete(self):
|
||||
def test_single_delete_process_eventrule(self):
|
||||
"""
|
||||
Check that deleting an object with an applicable EventRule queues a background task for the rule's action.
|
||||
"""
|
||||
site = Site.objects.create(name='Site 1', slug='site-1')
|
||||
site.tags.set(Tag.objects.filter(name__in=['Foo', 'Bar']))
|
||||
|
||||
@@ -214,17 +288,21 @@ class WebhookTest(APITestCase):
|
||||
response = self.client.delete(url, **self.header)
|
||||
self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
|
||||
|
||||
# Verify that a job was queued for the object update webhook
|
||||
# Verify that a task was queued for the deleted object
|
||||
self.assertEqual(self.queue.count, 1)
|
||||
job = self.queue.jobs[0]
|
||||
self.assertEqual(job.kwargs['webhook'], Webhook.objects.get(type_delete=True))
|
||||
self.assertEqual(job.kwargs['event_rule'], EventRule.objects.get(type_delete=True))
|
||||
self.assertEqual(job.kwargs['event'], ObjectChangeActionChoices.ACTION_DELETE)
|
||||
self.assertEqual(job.kwargs['model_name'], 'site')
|
||||
self.assertEqual(job.kwargs['data']['id'], site.pk)
|
||||
self.assertEqual(job.kwargs['snapshots']['prechange']['name'], 'Site 1')
|
||||
self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo'])
|
||||
|
||||
def test_enqueue_webhook_bulk_delete(self):
|
||||
def test_bulk_delete_process_eventrule(self):
|
||||
"""
|
||||
Check that bulk deleting multiple objects with an applicable EventRule queues a background task for each
|
||||
deleted object.
|
||||
"""
|
||||
sites = (
|
||||
Site(name='Site 1', slug='site-1'),
|
||||
Site(name='Site 2', slug='site-2'),
|
||||
@@ -243,49 +321,17 @@ class WebhookTest(APITestCase):
|
||||
response = self.client.delete(url, data, format='json', **self.header)
|
||||
self.assertHttpStatus(response, status.HTTP_204_NO_CONTENT)
|
||||
|
||||
# Verify that a job was queued for the object update webhook
|
||||
# Verify that a background task was queued for each deleted object
|
||||
self.assertEqual(self.queue.count, 3)
|
||||
for i, job in enumerate(self.queue.jobs):
|
||||
self.assertEqual(job.kwargs['webhook'], Webhook.objects.get(type_delete=True))
|
||||
self.assertEqual(job.kwargs['event_rule'], EventRule.objects.get(type_delete=True))
|
||||
self.assertEqual(job.kwargs['event'], ObjectChangeActionChoices.ACTION_DELETE)
|
||||
self.assertEqual(job.kwargs['model_name'], 'site')
|
||||
self.assertEqual(job.kwargs['data']['id'], sites[i].pk)
|
||||
self.assertEqual(job.kwargs['snapshots']['prechange']['name'], sites[i].name)
|
||||
self.assertEqual(job.kwargs['snapshots']['prechange']['tags'], ['Bar', 'Foo'])
|
||||
|
||||
def test_webhook_conditions(self):
|
||||
# Create a conditional Webhook
|
||||
webhook = Webhook(
|
||||
name='Conditional Webhook',
|
||||
type_create=True,
|
||||
type_update=True,
|
||||
payload_url='http://localhost:9000/',
|
||||
conditions={
|
||||
'and': [
|
||||
{
|
||||
'attr': 'status.value',
|
||||
'value': 'active',
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
# Create a Site to evaluate
|
||||
site = Site.objects.create(name='Site 1', slug='site-1', status=SiteStatusChoices.STATUS_STAGING)
|
||||
data = serialize_for_webhook(site)
|
||||
|
||||
# Evaluate the conditions (status='staging')
|
||||
self.assertFalse(eval_conditions(webhook, data))
|
||||
|
||||
# Change the site's status
|
||||
site.status = SiteStatusChoices.STATUS_ACTIVE
|
||||
data = serialize_for_webhook(site)
|
||||
|
||||
# Evaluate the conditions (status='active')
|
||||
self.assertTrue(eval_conditions(webhook, data))
|
||||
|
||||
def test_webhooks_worker(self):
|
||||
|
||||
request_id = uuid.uuid4()
|
||||
|
||||
def dummy_send(_, request, **kwargs):
|
||||
@@ -293,7 +339,8 @@ class WebhookTest(APITestCase):
|
||||
A dummy implementation of Session.send() to be used for testing.
|
||||
Always returns a 200 HTTP response.
|
||||
"""
|
||||
webhook = Webhook.objects.get(type_create=True)
|
||||
event = EventRule.objects.get(type_create=True)
|
||||
webhook = event.action_object
|
||||
signature = generate_signature(request.body, webhook.secret)
|
||||
|
||||
# Validate the outgoing request headers
|
||||
@@ -322,7 +369,7 @@ class WebhookTest(APITestCase):
|
||||
request_id=request_id,
|
||||
action=ObjectChangeActionChoices.ACTION_CREATE
|
||||
)
|
||||
flush_webhooks(webhooks_queue)
|
||||
flush_events(webhooks_queue)
|
||||
|
||||
# Retrieve the job from queue
|
||||
job = self.queue.jobs[0]
|
||||
@@ -6,6 +6,7 @@ from django.contrib.contenttypes.models import ContentType
|
||||
from django.test import TestCase
|
||||
|
||||
from circuits.models import Provider
|
||||
from core.choices import ManagedFileRootPathChoices
|
||||
from dcim.filtersets import SiteFilterSet
|
||||
from dcim.models import DeviceRole, DeviceType, Manufacturer, Platform, Rack, Region, Site, SiteGroup
|
||||
from dcim.models import Location
|
||||
@@ -159,82 +160,174 @@ class WebhookTestCase(TestCase, BaseFilterSetTests):
|
||||
webhooks = (
|
||||
Webhook(
|
||||
name='Webhook 1',
|
||||
type_create=True,
|
||||
type_update=False,
|
||||
type_delete=False,
|
||||
type_job_start=False,
|
||||
type_job_end=False,
|
||||
payload_url='http://example.com/?1',
|
||||
enabled=True,
|
||||
http_method='GET',
|
||||
ssl_verification=True,
|
||||
),
|
||||
Webhook(
|
||||
name='Webhook 2',
|
||||
type_create=False,
|
||||
type_update=True,
|
||||
type_delete=False,
|
||||
type_job_start=False,
|
||||
type_job_end=False,
|
||||
payload_url='http://example.com/?2',
|
||||
enabled=True,
|
||||
http_method='POST',
|
||||
ssl_verification=True,
|
||||
),
|
||||
Webhook(
|
||||
name='Webhook 3',
|
||||
type_create=False,
|
||||
type_update=False,
|
||||
type_delete=True,
|
||||
type_job_start=False,
|
||||
type_job_end=False,
|
||||
payload_url='http://example.com/?3',
|
||||
enabled=False,
|
||||
http_method='PATCH',
|
||||
ssl_verification=False,
|
||||
),
|
||||
Webhook(
|
||||
name='Webhook 4',
|
||||
type_create=False,
|
||||
type_update=False,
|
||||
type_delete=False,
|
||||
type_job_start=True,
|
||||
type_job_end=False,
|
||||
payload_url='http://example.com/?4',
|
||||
enabled=False,
|
||||
http_method='PATCH',
|
||||
ssl_verification=False,
|
||||
),
|
||||
Webhook(
|
||||
name='Webhook 5',
|
||||
type_create=False,
|
||||
type_update=False,
|
||||
type_delete=False,
|
||||
type_job_start=False,
|
||||
type_job_end=True,
|
||||
payload_url='http://example.com/?5',
|
||||
enabled=False,
|
||||
http_method='PATCH',
|
||||
ssl_verification=False,
|
||||
),
|
||||
)
|
||||
Webhook.objects.bulk_create(webhooks)
|
||||
webhooks[0].content_types.add(content_types[0])
|
||||
webhooks[1].content_types.add(content_types[1])
|
||||
webhooks[2].content_types.add(content_types[2])
|
||||
webhooks[3].content_types.add(content_types[3])
|
||||
webhooks[4].content_types.add(content_types[4])
|
||||
|
||||
def test_name(self):
|
||||
params = {'name': ['Webhook 1', 'Webhook 2']}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_http_method(self):
|
||||
params = {'http_method': ['GET', 'POST']}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_ssl_verification(self):
|
||||
params = {'ssl_verification': True}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
|
||||
class EventRuleTestCase(TestCase, BaseFilterSetTests):
|
||||
queryset = EventRule.objects.all()
|
||||
filterset = EventRuleFilterSet
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
content_types = ContentType.objects.filter(
|
||||
model__in=['region', 'site', 'rack', 'location', 'device']
|
||||
)
|
||||
|
||||
webhooks = (
|
||||
Webhook(
|
||||
name='Webhook 1',
|
||||
payload_url='http://example.com/?1',
|
||||
),
|
||||
Webhook(
|
||||
name='Webhook 2',
|
||||
payload_url='http://example.com/?2',
|
||||
),
|
||||
Webhook(
|
||||
name='Webhook 3',
|
||||
payload_url='http://example.com/?3',
|
||||
),
|
||||
)
|
||||
Webhook.objects.bulk_create(webhooks)
|
||||
|
||||
scripts = (
|
||||
ScriptModule(
|
||||
file_root=ManagedFileRootPathChoices.SCRIPTS,
|
||||
file_path='/var/tmp/script1.py'
|
||||
),
|
||||
ScriptModule(
|
||||
file_root=ManagedFileRootPathChoices.SCRIPTS,
|
||||
file_path='/var/tmp/script2.py'
|
||||
),
|
||||
)
|
||||
ScriptModule.objects.bulk_create(scripts)
|
||||
|
||||
event_rules = (
|
||||
EventRule(
|
||||
name='Event Rule 1',
|
||||
action_object=webhooks[0],
|
||||
enabled=True,
|
||||
type_create=True,
|
||||
type_update=False,
|
||||
type_delete=False,
|
||||
type_job_start=False,
|
||||
type_job_end=False,
|
||||
action_type=EventRuleActionChoices.WEBHOOK,
|
||||
),
|
||||
EventRule(
|
||||
name='Event Rule 2',
|
||||
action_object=webhooks[1],
|
||||
enabled=True,
|
||||
type_create=False,
|
||||
type_update=True,
|
||||
type_delete=False,
|
||||
type_job_start=False,
|
||||
type_job_end=False,
|
||||
action_type=EventRuleActionChoices.WEBHOOK,
|
||||
),
|
||||
EventRule(
|
||||
name='Event Rule 3',
|
||||
action_object=webhooks[2],
|
||||
enabled=False,
|
||||
type_create=False,
|
||||
type_update=False,
|
||||
type_delete=True,
|
||||
type_job_start=False,
|
||||
type_job_end=False,
|
||||
action_type=EventRuleActionChoices.WEBHOOK,
|
||||
),
|
||||
EventRule(
|
||||
name='Event Rule 4',
|
||||
action_object=scripts[0],
|
||||
enabled=False,
|
||||
type_create=False,
|
||||
type_update=False,
|
||||
type_delete=False,
|
||||
type_job_start=True,
|
||||
type_job_end=False,
|
||||
action_type=EventRuleActionChoices.SCRIPT,
|
||||
),
|
||||
EventRule(
|
||||
name='Event Rule 5',
|
||||
action_object=scripts[1],
|
||||
enabled=False,
|
||||
type_create=False,
|
||||
type_update=False,
|
||||
type_delete=False,
|
||||
type_job_start=False,
|
||||
type_job_end=True,
|
||||
action_type=EventRuleActionChoices.SCRIPT,
|
||||
),
|
||||
)
|
||||
EventRule.objects.bulk_create(event_rules)
|
||||
event_rules[0].content_types.add(content_types[0])
|
||||
event_rules[1].content_types.add(content_types[1])
|
||||
event_rules[2].content_types.add(content_types[2])
|
||||
event_rules[3].content_types.add(content_types[3])
|
||||
event_rules[4].content_types.add(content_types[4])
|
||||
|
||||
def test_name(self):
|
||||
params = {'name': ['Event Rule 1', 'Event Rule 2']}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_content_types(self):
|
||||
params = {'content_types': 'dcim.region'}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||
params = {'content_type_id': [ContentType.objects.get_for_model(Region).pk]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||
|
||||
def test_action_type(self):
|
||||
params = {'action_type': [EventRuleActionChoices.WEBHOOK]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||
params = {'action_type': [EventRuleActionChoices.SCRIPT]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_enabled(self):
|
||||
params = {'enabled': True}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
params = {'enabled': False}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||
|
||||
def test_type_create(self):
|
||||
params = {'type_create': True}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||
@@ -255,18 +348,6 @@ class WebhookTestCase(TestCase, BaseFilterSetTests):
|
||||
params = {'type_job_end': True}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||
|
||||
def test_enabled(self):
|
||||
params = {'enabled': True}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_http_method(self):
|
||||
params = {'http_method': ['GET', 'POST']}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_ssl_verification(self):
|
||||
params = {'ssl_verification': True}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
|
||||
class CustomLinkTestCase(TestCase, BaseFilterSetTests):
|
||||
queryset = CustomLink.objects.all()
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
import urllib.parse
|
||||
import uuid
|
||||
|
||||
@@ -11,7 +10,6 @@ from extras.choices import *
|
||||
from extras.models import *
|
||||
from utilities.testing import ViewTestCases, TestCase
|
||||
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
@@ -336,33 +334,26 @@ class WebhookTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
||||
site_ct = ContentType.objects.get_for_model(Site)
|
||||
webhooks = (
|
||||
Webhook(name='Webhook 1', payload_url='http://example.com/?1', type_create=True, http_method='POST'),
|
||||
Webhook(name='Webhook 2', payload_url='http://example.com/?2', type_create=True, http_method='POST'),
|
||||
Webhook(name='Webhook 3', payload_url='http://example.com/?3', type_create=True, http_method='POST'),
|
||||
Webhook(name='Webhook 1', payload_url='http://example.com/?1', http_method='POST'),
|
||||
Webhook(name='Webhook 2', payload_url='http://example.com/?2', http_method='POST'),
|
||||
Webhook(name='Webhook 3', payload_url='http://example.com/?3', http_method='POST'),
|
||||
)
|
||||
for webhook in webhooks:
|
||||
webhook.save()
|
||||
webhook.content_types.add(site_ct)
|
||||
|
||||
cls.form_data = {
|
||||
'name': 'Webhook X',
|
||||
'content_types': [site_ct.pk],
|
||||
'type_create': False,
|
||||
'type_update': True,
|
||||
'type_delete': True,
|
||||
'payload_url': 'http://example.com/?x',
|
||||
'http_method': 'GET',
|
||||
'http_content_type': 'application/foo',
|
||||
'conditions': None,
|
||||
}
|
||||
|
||||
cls.csv_data = (
|
||||
"name,content_types,type_create,payload_url,http_method,http_content_type",
|
||||
"Webhook 4,dcim.site,True,http://example.com/?4,GET,application/json",
|
||||
"Webhook 5,dcim.site,True,http://example.com/?5,GET,application/json",
|
||||
"Webhook 6,dcim.site,True,http://example.com/?6,GET,application/json",
|
||||
"name,payload_url,http_method,http_content_type",
|
||||
"Webhook 4,http://example.com/?4,GET,application/json",
|
||||
"Webhook 5,http://example.com/?5,GET,application/json",
|
||||
"Webhook 6,http://example.com/?6,GET,application/json",
|
||||
)
|
||||
|
||||
cls.csv_update_data = (
|
||||
@@ -373,11 +364,62 @@ class WebhookTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
)
|
||||
|
||||
cls.bulk_edit_data = {
|
||||
'enabled': False,
|
||||
'http_method': 'GET',
|
||||
}
|
||||
|
||||
|
||||
class EventRulesTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
model = EventRule
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
||||
webhooks = (
|
||||
Webhook(name='Webhook 1', payload_url='http://example.com/?1', http_method='POST'),
|
||||
Webhook(name='Webhook 2', payload_url='http://example.com/?2', http_method='POST'),
|
||||
Webhook(name='Webhook 3', payload_url='http://example.com/?3', http_method='POST'),
|
||||
)
|
||||
for webhook in webhooks:
|
||||
webhook.save()
|
||||
|
||||
site_ct = ContentType.objects.get_for_model(Site)
|
||||
event_rules = (
|
||||
EventRule(name='EventRule 1', type_create=True, action_object=webhooks[0]),
|
||||
EventRule(name='EventRule 2', type_create=True, action_object=webhooks[1]),
|
||||
EventRule(name='EventRule 3', type_create=True, action_object=webhooks[2]),
|
||||
)
|
||||
for event in event_rules:
|
||||
event.save()
|
||||
event.content_types.add(site_ct)
|
||||
|
||||
webhook_ct = ContentType.objects.get_for_model(Webhook)
|
||||
cls.form_data = {
|
||||
'name': 'Event X',
|
||||
'content_types': [site_ct.pk],
|
||||
'type_create': False,
|
||||
'type_update': True,
|
||||
'type_delete': True,
|
||||
'http_method': 'GET',
|
||||
'conditions': None,
|
||||
'action_type': 'webhook',
|
||||
'action_object_type': webhook_ct.pk,
|
||||
'action_object_id': webhooks[0].pk,
|
||||
'action_choice': webhooks[0]
|
||||
}
|
||||
|
||||
cls.csv_data = (
|
||||
"name,content_types,type_create,action_type,action_object",
|
||||
"Webhook 4,dcim.site,True,webhook,Webhook 1",
|
||||
)
|
||||
|
||||
cls.csv_update_data = (
|
||||
"id,name",
|
||||
f"{event_rules[0].pk},Event 7",
|
||||
f"{event_rules[1].pk},Event 8",
|
||||
f"{event_rules[2].pk},Event 9",
|
||||
)
|
||||
|
||||
cls.bulk_edit_data = {
|
||||
'type_update': True,
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user