From df8b8b2b423e78032d2e89c8d3f33cef3cf0e889 Mon Sep 17 00:00:00 2001 From: Viktor Tsvetkov <142901247+vtsvetkov-splunk@users.noreply.github.com> Date: Thu, 26 Sep 2024 08:20:24 +0200 Subject: [PATCH] feat: add ability to get console logs (#434) [ADDON-73881](https://splunk.atlassian.net/browse/ADDON-73881) As a smartx enjoyer, I want to get access to the browser console logs to fail my tests if there are JS errors. ## Changes - Add capability to track logs in Chrome - Add a helper to access an array of logs ## Example of usage ```python severe_console_logs = get_browser_logs(ucc_smartx_selenium_helper.browser, log_level=LogLevel.SEVERE, log_source=LogSource.CONSOLE_API) assert not severe_console_logs, f"Unexpected severe console logs found: {severe_console_logs}" ``` Currently, this feature is only supported with the Chrome browser. Analysis on adding support for other browser: https://splunk.atlassian.net/browse/ADDON-73881?focusedCommentId=15449369 --------- Co-authored-by: Darshan Varasani --- pytest_splunk_addon_ui_smartx/base_test.py | 1 + pytest_splunk_addon_ui_smartx/utils.py | 57 +++++++++++++++++++ .../test_splunk_ta_example_addon_logging.py | 24 ++++++++ 3 files changed, 82 insertions(+) diff --git a/pytest_splunk_addon_ui_smartx/base_test.py b/pytest_splunk_addon_ui_smartx/base_test.py index a1e0364f..deff338c 100644 --- a/pytest_splunk_addon_ui_smartx/base_test.py +++ b/pytest_splunk_addon_ui_smartx/base_test.py @@ -151,6 +151,7 @@ def get_local_ie_opts(): @staticmethod def get_local_chrome_opts(headless_run): chrome_opts = webdriver.ChromeOptions() + chrome_opts.set_capability("goog:loggingPrefs", {"browser": "ALL"}) chrome_opts.add_argument("--ignore-ssl-errors=yes") chrome_opts.add_argument("--ignore-certificate-errors") chrome_opts.add_argument("--disable-dev-shm-usage") diff --git a/pytest_splunk_addon_ui_smartx/utils.py b/pytest_splunk_addon_ui_smartx/utils.py index cbac5010..84a63d2b 100644 --- a/pytest_splunk_addon_ui_smartx/utils.py +++ b/pytest_splunk_addon_ui_smartx/utils.py @@ -13,6 +13,11 @@ # See the License for the specific language governing permissions and # limitations under the License. # + +from typing import List, NamedTuple, Optional +from enum import Enum, auto + + def backend_retry(retry_count): # The decorator itself def backend_retry_decorator(method): @@ -33,3 +38,55 @@ def retry_method(*args, **kwargs): return retry_method return backend_retry_decorator + + +class LogLevel(Enum): + INFO = auto() + DEBUG = auto() + WARNING = auto() + SEVERE = auto() + + +class LogSource(Enum): + NETWORK = "network" + CONSOLE_API = "console-api" + RECOMMENDATION = "recommendation" + SECURITY = "security" + INTERVENTION = "intervention" + + +class LogEntry(NamedTuple): + level: LogLevel + message: str + source: LogSource + timestamp: int + + +def get_browser_logs( + browser, + log_level: Optional[LogLevel] = None, + log_source: Optional[LogSource] = None, +) -> List[LogEntry]: + """ + Retrieve and optionally filter browser console logs. + """ + if browser.name.lower() != "chrome": + return [] + + logs = browser.get_log("browser") + filtered_logs: List[LogEntry] = [] + + for log in logs: + entry = LogEntry( + level=LogLevel[log["level"]], + message=log["message"], + source=LogSource(log["source"]), + timestamp=log["timestamp"], + ) + + if (log_level is None or entry.level == log_level) and ( + log_source is None or entry.source == log_source + ): + filtered_logs.append(entry) + + return filtered_logs diff --git a/tests/ui/test_splunk_ta_example_addon_logging.py b/tests/ui/test_splunk_ta_example_addon_logging.py index 2f88425e..2fe50527 100644 --- a/tests/ui/test_splunk_ta_example_addon_logging.py +++ b/tests/ui/test_splunk_ta_example_addon_logging.py @@ -3,6 +3,8 @@ import pytest import random +from pytest_splunk_addon_ui_smartx.utils import LogSource, LogLevel, get_browser_logs + TA_NAME = "Splunk_TA_UCCExample" TA_CONF = "splunk_ta_uccexample_settings" @@ -31,4 +33,26 @@ def test_logging_select_random_log_level( level = random.choice(levels) logging.log_level.select(level) logging.save() + self.assert_util(logging.log_level.get_value().lower(), level.lower()) + + info_console_logs = get_browser_logs( + ucc_smartx_selenium_helper.browser, + log_level=LogLevel.INFO, + log_source=LogSource.CONSOLE_API, + ) + ucc_framework_logs = [ + log for log in info_console_logs if "UCC Framework" in log.message + ] + assert ( + len(ucc_framework_logs) > 0 + ), "No INFO log entry containing 'UCC Framework' found" + + severe_console_logs = get_browser_logs( + ucc_smartx_selenium_helper.browser, + log_level=LogLevel.SEVERE, + log_source=LogSource.CONSOLE_API, + ) + assert ( + len(severe_console_logs) == 0 + ), f"Unexpected severe console logs found: {severe_console_logs}"