Тестирование кода
В данном разделе рассматриваются основные аспекты создания тестов, включая использование заглушек, проверку полноты тестов, охват всех возможных сценариев и проведение тестов на производительность.
Инструкции по созданию тестов доступны в руководствах по созданию RObject-конфигураций элементов экспертизы. |
Заглушки
Заглушки — это специальные заменители, которые используются в тестах для изоляции конкретных участков кода. Они имитируют работу частей системы, которые не поддаются тестированию в данном контексте, например, внешние API или несуществующие компоненты. |
В тестах на основе заглушек важно гарантировать, что они правильно настроены, чтобы их использование не привело к ложным срабатываниям и некорректным результатам. Например, если заглушка возвращает неправильные данные, это может исказить результат теста, и его проверка не будет корректной.
Заглушки не должны создавать ложных срабатываний или неправильных выводов в процессе выполнения теста. |
Заглушки используются в следующих случаях:
-
Изоляция сложных зависимостей: заглушки могут заменить сложные или зависимые компоненты, которые сложно или невозможно протестировать, как, например, внешние веб-сервисы.
-
Ускорение тестов: заглушки могут значительно ускорить выполнение тестов, поскольку вместо реальных вызовов к базе данных, файловой системе или сети используется имитация их работы.
-
Тестирование ошибок и исключений: заглушки могут быть настроены так, чтобы имитировать ошибки, что полезно для проверки обработки исключительных ситуаций.
... tests: - name: Privilege escalation from admin to root events: - { "uid": "root", "suid": "admin", "cmd": "pytohn", "sproc":"python", "dproduct": "Ubuntu", "dvchost": "ubnt.land", "dvendor": "Linux", "mode": "0100600", "msg": [ "audit(1694421703.884:27001658):" ], "name": "", "params": [ "-m" ], "sourceIp": "10.150.50.115", "suser": "1000", "syscall": "221", "duid": "0"} assertion: !vrl | true
В данном примере заглушка используется для тестирования случая повышения привилегий с пользователя admin до root. В контексте данного теста не происходит выполнения реальных операций с привилегиями или вызовов системы, а проверка сводится к простому утверждению true
.
Неполное написание тестов
Тесты должны быть достаточно полными, чтобы гарантировать проверку всех ключевых параметров и состояний, особенно при работе с более сложными функциями или обработкой данных.
Ниже приведен пример неполного теста, который проверяет только одно условие (параметр appname
):
... tests: - name: "Test" events: - { "raw": {"appname": "testapp", "facility": "kern", "message": "test message"} } assertion: !vrl | assert_eq!(.[0].appname, "testapp")
Этот тест проверяет только значение поля appname
, но не включает другие важные параметры, такие как facility
и message
. Это может привести к пропуску ошибок в данных.
Оптимизированный тест должен включать проверки для всех важных параметров, таких как facility
и message
:
... tests: - name: "Test" events: - { "raw": {"appname": "testapp", "facility": "kern", "message": "test message"} } assertion: !vrl | assert_eq!(.[0].appname, "testapp") assert_eq!(.[0].facility, "kern") assert_eq!(.[0].message, "test message")
Рассмотрим пример теста нормализации, где необходимо проверить несколько полей.
... normalizer: !vrl | .dproduct = "metrics" .dvendor = to_string(.raw.namespace) ?? "" .name = to_string(.raw.tags.component_id) ?? "" .cnt = to_string(.raw.counter.value) ?? "" .cat = to_string(.raw.name) ?? "" tests: - name: add_resource1 events: - { "raw": {"appname":"testtag","facility":"kern","hostname":"host001","message":"13.03.2017 17:54.25 '# UserGate Server# ' 192.168.30.71 -> 188.40.238.250:80 0/440","procid":14884,"severity":"info","timestamp":"2024-02-27T16:14:41Z"}} assertion: !vrl | assert_eq!(.[0].bytesOut, null)
Для того чтобы исправить тест, нужно добавить проверку для каждого поля:
... tests: - name: "testing" events: - raw: {"counter":{"value":1751.0},"kind":"absolute","name":"component_received_event_bytes_total","namespace":"vector","tags":{"component_id":"unique-id-12345","component_kind":"transform","component_type":"remap","host":"collector-host-01"},"timestamp":"2024-05-29T10:26:42.688089484Z"} assertion: !vrl | assert_eq!(.[0].cat, "component_received_event_bytes_total") assert_eq!(.[0].cnt, "1751") assert_eq!(.[0].dvendor, "vector") assert_eq!(.[0].name, "unique-id-12345") assert_eq!(.[0].dproduct, "metrics")
Проверка всех сценариев
Тесты должны обеспечивать надежность и предсказуемость правил, чтобы исключить нежелательные срабатывания или пропуски.
Тестирование всех сценариев выполнения правил включает проверку корректной обработки событий, обработки некорректных данных, обработки исключений и проверки работы на граничных условиях.
Тесты можно разделить на несколько категорий:
-
Позитивные сценарии: проверка, что правило корректно обрабатывает события, соответствующие условиям.
-
Негативные сценарии: проверка, что некорректные или неподходящие события не приводят к срабатыванию правила.
-
Граничные случаи: тестирование минимальных, максимальных значений и редких комбинаций.
При описании тестов рекомендуется указывать цель проверки, чтобы упростить сопровождение кода. |
Для достижения полной проверки сценариев следует:
-
Убедиться, что тесты охватывают все логические ветки правил.
-
Проверить реакции правил на отсутствующие, лишние или неверные данные.
-
Включить тесты, моделирующие исключительные ситуации, например, пустые события, неожиданные форматы данных.
tests: - name: "Scenario 1: Basic network connection" description: Проверка корректного определения сетевого подключения. events: - { "type": "network", "action": "connect", "source_ip": "192.0.2.1" } assertion: !vrl | assert_eq!(.[0].type, "network") && assert_eq!(.[0].action, "connect") && assert_eq!(.[0].source_ip, "192.0.2.1") - name: "Eventid 7: wmic process list using wmiscript.xsl" description: Проверка обработки события с использованием `wmic` и `wmiscript.xsl`. events: - { "dvchost": "host1.domain.local", "fname": "C:\\Windows\\System32\\wmiscript.dll" } assertion: !vrl | assert_eq!(.[0].dvchost, "host1.domain.local") && assert_eq!(.[0].fname, "C:\\Windows\\System32\\wmiscript.dll") - name: "Eventid 7: msxsl processing msxscript.xsl" description: Проверка корректного распознавания использования `msxsl` и `msxscript.xsl`. events: - { "dvchost": "host1.domain.local", "fname": "C:\\Windows\\System32\\msxscript.dll" } assertion: !vrl | assert_eq!(.[0].dvchost, "host1.domain.local") && assert_eq!(.[0].fname, "C:\\Windows\\System32\\msxscript.dll") - name: "Eventid 4688: msxsl loading xsl over network" description: Проверка загрузки `.xsl` через SMB-сетевой путь. events: - { "dvchost": "host1.domain.local", "fname": "\\x.x.x.x\\mysmbshare\\file1.xsl" } assertion: !vrl | assert_eq!(.[0].dvchost, "host1.domain.local") && assert_eq!(.[0].fname, "\\x.x.x.x\\mysmbshare\\file1.xsl") - name: "Eventid 1: wmic process execution" description: Проверка выполнения команды через `wmic`. events: - { "dvchost": "host1.domain.local", "fname": "C:\\Windows\\System32\\cmd.exe" } assertion: !vrl | assert_eq!(.[0].dvchost, "host1.domain.local") && assert_eq!(.[0].fname, "C:\\Windows\\System32\\cmd.exe") - name: "Eventid 1: msxsl executing calc.exe" description: Проверка выполнения `calc.exe` через `msxsl`. events: - { "dvchost": "host1.domain.local", "sproc": "C:\\Windows\\System32\\cmd.exe" } assertion: !vrl | assert_eq!(.[0].dvchost, "host1.domain.local") && assert_eq!(.[0].sproc, "C:\\Windows\\System32\\cmd.exe") - name: "Eventid 1: msxsl.exe from known hash" description: Проверка выполнения `msxsl.exe` из известного пути. events: - { "dvchost": "host1.domain.local", "dproc": "C:\\System\\Payloads\\msxsl.exe" } assertion: !vrl | assert_eq!(.[0].dvchost, "host1.domain.local") && assert_eq!(.[0].dproc, "C:\\System\\Payloads\\msxsl.exe") - name: "Eventid 1: msxsl.exe from random file" description: Проверка выполнения произвольного файла вместо ожидаемого. events: - { "dvchost": "host1.domain.local", "dproc": "C:\\System\\Payloads\\456.exe" } assertion: !vrl | assert_eq!(.[0].dvchost, "host1.domain.local") && assert_eq!(.[0].dproc, "C:\\System\\Payloads\\456.exe")
Тесты на производительность
Производительность правил должна проверяться с помощью специализированных тестов, направленных на выявление узких мест в обработке большого объема событий. Это позволяет гарантировать, что система будет эффективно работать даже при высокой нагрузке и большом объеме данных.
Тесты на производительность обычно включают в себя создание набора событий, который имитирует реальные условия работы системы, и их многократную обработку для оценки времени выполнения правил. Для этого используется параметр repetitions
, который задает количество повторений для каждого теста, что помогает оценить стабильность работы в условиях высоких нагрузок.
... benches: - name: "Performance Test" repetitions: 10000 events: - { "raw": "2022-08-11T12:32:41.000Z 5.86.210.12 - user=user2 act=file op=del host=pc1 name=pomodoro.txt" } ...
В данном примере выполняется тест с 10 000 повторениями, где для каждого события генерируется строка, содержащая информацию о файле и операции с ним. Это позволяет проверить, насколько эффективно правило обрабатывает множество таких событий в течение длительного времени.