305 lines
14 KiB
Python
305 lines
14 KiB
Python
import datetime
|
|
import json
|
|
from secrets import choice
|
|
from unittest.mock import patch
|
|
|
|
import fakeredis
|
|
from unittest import mock
|
|
import pytest
|
|
from django.contrib.auth import get_user_model
|
|
from django.urls import reverse
|
|
|
|
from assets.models.assets import OperatingSystem, Asset
|
|
# noinspection PyUnresolvedReferences
|
|
from console.tests.test_utils import add_user_with_permissions, get_url, test_server
|
|
from core.utils import dtnow
|
|
from dashboard.models import DashboardLayout
|
|
# TODO: enable when correlator is ready
|
|
# from dashboard.tasks import update_incs_by_time_statistics, update_events_by_time_statistics
|
|
from dashboard.tasks import update_incs_by_time_statistics
|
|
from dashboard.utils import RedisInstances
|
|
from dashboard.views import check_user_widgets
|
|
from incident.models import Incident
|
|
from networkmap.api import DANGER_STATUSES
|
|
from perms.models import Perm
|
|
from users.models import UserInfo
|
|
|
|
# from dashboard.serializers import DashboardSerializer
|
|
|
|
User = get_user_model()
|
|
|
|
real_datetime_class = datetime.datetime
|
|
USERNAME = 'test_not_superuser'
|
|
PASSWORD = 'test_password'
|
|
|
|
|
|
def mock_datetime_now(target, dt):
|
|
class DatetimeSubclassMeta(type):
|
|
@classmethod
|
|
def __instancecheck__(mcs, obj):
|
|
return isinstance(obj, real_datetime_class)
|
|
|
|
class BaseMockedDatetime(real_datetime_class):
|
|
@classmethod
|
|
def now(cls, tz=None):
|
|
return target.replace(tzinfo=tz)
|
|
|
|
@classmethod
|
|
def utcnow(cls):
|
|
return target
|
|
|
|
# Python2 & Python3 compatible metaclass
|
|
MockedDatetime = DatetimeSubclassMeta('datetime', (BaseMockedDatetime,), {})
|
|
|
|
return mock.patch.object(dt, 'datetime', MockedDatetime)
|
|
|
|
|
|
@pytest.mark.django_db
|
|
class TestApi(object):
|
|
|
|
@pytest.fixture(autouse=True)
|
|
def testing_redis(self, django_user_model):
|
|
server = fakeredis.FakeServer()
|
|
test_redis = fakeredis.FakeStrictRedis(server=server)
|
|
test_redis.set(RedisInstances.WIDGET_INCS_BY_TIME_DAY, json.dumps([0] * 24))
|
|
test_redis.set(RedisInstances.WIDGET_INCS_BY_TIME_WEEK, json.dumps([0] * 7))
|
|
test_redis.set(RedisInstances.WIDGET_INCS_BY_TIME_MONTH, json.dumps([0] * 30))
|
|
test_redis.set(RedisInstances.WIDGET_INCS_BY_TIME_YEAR, json.dumps([0] * 12))
|
|
test_redis.set(RedisInstances.WIDGET_EVENTS_BY_TIME_DAY, json.dumps([0] * 24))
|
|
test_redis.set(RedisInstances.WIDGET_EVENTS_BY_TIME_WEEK, json.dumps([0] * 7))
|
|
test_redis.set(RedisInstances.WIDGET_EVENTS_BY_TIME_MONTH, json.dumps([0] * 30))
|
|
test_redis.set(RedisInstances.WIDGET_EVENTS_BY_TIME_YEAR, json.dumps([0] * 12))
|
|
redis_patcher = patch('dashboard.tasks.redis_instance', test_redis)
|
|
self.redis = redis_patcher.start()
|
|
|
|
user1 = django_user_model.objects.create_superuser(username='admin400', password='nimda')
|
|
user2 = django_user_model.objects.create_user(username=USERNAME, password=PASSWORD)
|
|
UserInfo(user=user1).save()
|
|
UserInfo(user=user2).save()
|
|
|
|
return test_redis
|
|
|
|
@pytest.mark.unit
|
|
def test_inccidents_by_time_hour_task(self, testing_redis):
|
|
""" Test for checking the celery task for incidents by time widget past hour incident sum
|
|
Steps of the test:
|
|
1. Get REDIS data before invoking task
|
|
2. Create 2 incidents
|
|
3. Run task again
|
|
4. Check if value of day stats in REDIS changed
|
|
:param testing_redis: fixture for initializing testing REDIS instance
|
|
"""
|
|
day_data_before = json.loads(testing_redis.get(RedisInstances.WIDGET_INCS_BY_TIME_DAY))
|
|
Incident.objects.create(timestamp=dtnow(), title='test_inc_1', importance=1, status=2, event_count=1, events='')
|
|
update_incs_by_time_statistics()
|
|
day_data_after = json.loads(testing_redis.get(RedisInstances.WIDGET_INCS_BY_TIME_DAY))
|
|
assert day_data_before != day_data_after
|
|
|
|
@pytest.mark.unit
|
|
def test_incidents_by_time_week_update(self, testing_redis):
|
|
""" Test for checking the data for incidents by time widget (week data), when day changes
|
|
Steps of the test:
|
|
1. Create 3 incidents with the last of which occurs the day after the first two
|
|
2. Every time incidents created, call update widget data function
|
|
3. Compare last value of week data with 3 (sum of incidents)
|
|
:param testing_redis:
|
|
"""
|
|
for i in range(3):
|
|
incident_datetime = datetime.datetime(2020, 1, 1, 21, 59, 0, 0, None) + datetime.timedelta(hours=i)
|
|
|
|
def dtnow_for_widgets(minutes=0):
|
|
hours_from_dtnow_call = minutes
|
|
return incident_datetime + datetime.timedelta(minutes=1, hours=hours_from_dtnow_call)
|
|
|
|
with patch('dashboard.tasks.dtnow', dtnow_for_widgets):
|
|
created_inc = Incident.objects.create(timestamp=incident_datetime,
|
|
title=f"test_inc{i}",
|
|
importance=1,
|
|
status=2,
|
|
event_count=1,
|
|
events='')
|
|
update_incs_by_time_statistics()
|
|
week_stats = json.loads(testing_redis.get(RedisInstances.WIDGET_INCS_BY_TIME_WEEK))
|
|
assert week_stats[-1] == 1
|
|
|
|
@pytest.mark.unit
|
|
def test_incidents_by_time_month_update(self, testing_redis):
|
|
""" Test for checking the data for incidents by time widget (month data), when day changes
|
|
Steps of the test:
|
|
1. Create 3 incidents with the last of which occurs the day after the first two
|
|
2. Every time incidents created, call update widget data function
|
|
3. Compare last value of week data with 3 (sum of incidents)
|
|
:param testing_redis:
|
|
"""
|
|
for i in range(3):
|
|
incident_datetime = datetime.datetime(2020, 1, 1, 21, 59, 0, 0, None) + datetime.timedelta(hours=i)
|
|
|
|
def dtnow_for_widgets(minutes=0):
|
|
hours_from_dtnow_call = minutes
|
|
return incident_datetime + datetime.timedelta(minutes=1, hours=hours_from_dtnow_call)
|
|
|
|
with patch('dashboard.tasks.dtnow', dtnow_for_widgets):
|
|
created_inc = Incident.objects.create(timestamp=incident_datetime,
|
|
title=f"test_inc{i}",
|
|
importance=1,
|
|
status=2,
|
|
event_count=1,
|
|
events='')
|
|
update_incs_by_time_statistics()
|
|
month_stats = json.loads(testing_redis.get(RedisInstances.WIDGET_INCS_BY_TIME_MONTH))
|
|
assert month_stats[-1] == 1
|
|
|
|
@pytest.mark.unit
|
|
def test_incidents_by_time_year_update(self, testing_redis):
|
|
""" Test for checking the data for incidents by time widget (month data), when day changes
|
|
Steps of the test:
|
|
1. Create 3 incidents with the last of which occurs the day after the first two and on next month
|
|
2. Every time incidents created, call update widget data function
|
|
3. Compare last value of week data with 3 (sum of incidents)
|
|
:param testing_redis: fixture for initializing testing REDIS instance
|
|
"""
|
|
for i in range(3):
|
|
incident_datetime = datetime.datetime(2020, 1, 31, 21, 59, 0, 0, None) + datetime.timedelta(hours=i)
|
|
|
|
def dtnow_for_widgets(minutes=0):
|
|
hours_from_dtnow_call = minutes
|
|
return incident_datetime + datetime.timedelta(minutes=1, hours=hours_from_dtnow_call)
|
|
|
|
with patch('dashboard.tasks.dtnow', dtnow_for_widgets):
|
|
created_inc = Incident.objects.create(timestamp=incident_datetime,
|
|
title=f"test_inc{i}",
|
|
importance=1,
|
|
status=2,
|
|
event_count=1,
|
|
events='')
|
|
update_incs_by_time_statistics()
|
|
year_stats = json.loads(testing_redis.get(RedisInstances.WIDGET_INCS_BY_TIME_YEAR))
|
|
assert year_stats[-1] == 1
|
|
|
|
@pytest.mark.unit
|
|
def test_assets_by_incs_widget_counting_right_incidents(self, get_url, client):
|
|
"""
|
|
Test for checking if widget backend correctly counts right incidents
|
|
Steps of the test:
|
|
1. Create asset for testing purposes
|
|
2. Create 3 incidents with statuses within DANGER_STATUSES list and assign them to the asset from step 1
|
|
3. Run widget backend
|
|
4. Change status of one created incident to RESOLVED
|
|
5. Run widget backend again
|
|
6. Compare results of step 2 and 4
|
|
:return:
|
|
PASSED if values are not equal
|
|
FAILED if not
|
|
"""
|
|
test_os = OperatingSystem.objects.create(name='test_OS')
|
|
test_asset = Asset.objects.create(name='test_asset', ip='1.1.1.1', os=test_os)
|
|
for i in range(3):
|
|
test_inc = Incident.objects.create(timestamp=dtnow(),
|
|
title=f"test_inc{i}",
|
|
importance=1,
|
|
status=choice(DANGER_STATUSES),
|
|
event_count=1,
|
|
events='')
|
|
test_asset.incidents.add(test_inc)
|
|
url = reverse('assets_by_incs-list')
|
|
client.force_login(User.objects.get(username='admin400'))
|
|
response = client.get(url)
|
|
response_result_before = json.loads(response.content.decode('utf-8'))
|
|
inc_count_before = response_result_before[0].get('inc_count')
|
|
changing_inc = Incident.objects.get(title='test_inc1')
|
|
changing_inc.status = Incident.Status.RESOLVED
|
|
changing_inc.save()
|
|
response = client.get(url)
|
|
response_result_after = json.loads(response.content.decode('utf-8'))
|
|
inc_count_after = response_result_after[0].get('inc_count')
|
|
assert inc_count_after != inc_count_before
|
|
|
|
@pytest.mark.unit
|
|
def test_opened_incs_widget_counter(self, client):
|
|
"""
|
|
Test for checking if widget backend correctly counts opened widgets
|
|
Steps of the test:
|
|
1. Create incidents with statuses within DANGER_STATUSES list
|
|
2. Run widget backend
|
|
3. Change status of 1 incident from step 1 to RESOLVED
|
|
4. Run backend again
|
|
5. Compare results of step 2 and step 4
|
|
:param client: django testing client
|
|
:return:
|
|
PASSED if values are not equal
|
|
FAILED othervise
|
|
"""
|
|
for i in range(3):
|
|
Incident.objects.create(timestamp=dtnow(),
|
|
title=f"test_inc{i}",
|
|
importance=1,
|
|
status=choice(DANGER_STATUSES),
|
|
event_count=1,
|
|
events='')
|
|
url = reverse('opened_incs')
|
|
client.force_login(User.objects.get(username='admin400'))
|
|
response = client.get(url)
|
|
response_result_before = json.loads(response.content.decode('utf-8'))
|
|
count_before = response_result_before.get('inc_count')
|
|
changing_inc = Incident.objects.get(title='test_inc1')
|
|
changing_inc.status = Incident.Status.RESOLVED
|
|
changing_inc.save()
|
|
response = client.get(url)
|
|
response_result_after = json.loads(response.content.decode('utf-8'))
|
|
count_after = response_result_after.get('inc_count')
|
|
assert count_before != count_after
|
|
|
|
@pytest.mark.unit
|
|
@pytest.mark.parametrize('user_perms, result_count, widget_name', [
|
|
([], 0, ''),
|
|
([Perm.can_view_correlation_rules_list], 1, 'correlator-info'),
|
|
([[Perm.can_view_sys_info], 2, 'sys-info']),
|
|
])
|
|
def test_user_allowed_widgets(self, client, user_perms: list, result_count: int, widget_name: str):
|
|
""" Test for checking the filtration of user system information and services widget,
|
|
depending on his permissions
|
|
"""
|
|
# Getting testing user
|
|
test_user = User.objects.get(username=USERNAME)
|
|
# Getting user dashboard instance
|
|
widgets_before = DashboardLayout.objects.get(user=test_user)
|
|
# Adding testing widgets to users dashboard
|
|
widgets_before.widgets = [
|
|
{
|
|
"x": "0",
|
|
"y": "0",
|
|
"id": "sys-info",
|
|
"width": "2",
|
|
"height": "5"
|
|
},
|
|
{
|
|
"x": "2",
|
|
"y": "5",
|
|
"id": "services",
|
|
"width": "2",
|
|
"height": "5"
|
|
},
|
|
{
|
|
"x": "4",
|
|
"y": "10",
|
|
"id": "correlator-info",
|
|
"width": "2",
|
|
"height": "5"
|
|
},
|
|
{
|
|
"x": "6",
|
|
"y": "15",
|
|
"id": "incs-by-category",
|
|
"width": "2",
|
|
"height": "5"
|
|
},
|
|
]
|
|
widgets_before.save()
|
|
|
|
[test_user.user_permissions.add(Perm.get_rights(perm)) for perm in user_perms]
|
|
check_user_widgets(test_user)
|
|
widgets_after = DashboardLayout.objects.get(user=test_user)
|
|
|
|
assert len(widgets_after.widgets) == result_count
|
|
if result_count:
|
|
assert widgets_after.widgets[0]['id'] == widget_name
|