✨feat(project): add from-mails command
add `from-mails` command that connect to the mailbox using configurations in .env file, parse, classify and report all not analyzed files.
This commit is contained in:
+18
-9
@@ -40,7 +40,7 @@ def get_argument_from_files(log_dir: Path, output_path: Path) -> list[str]:
|
||||
str(file) for file in log_dir.iterdir() if file.suffix in ("", ".txt", ".log")
|
||||
]
|
||||
|
||||
arguments = ["--output-dir", str(output_path)]
|
||||
arguments = ["from-files", "--output-dir", str(output_path)]
|
||||
for file in files:
|
||||
arguments += ["--input-files", file]
|
||||
return arguments
|
||||
@@ -55,11 +55,10 @@ def test_cli_help():
|
||||
"""
|
||||
results = runner.invoke(app, ["--help"])
|
||||
assert results.exit_code == 0
|
||||
assert "Usage: cli [OPTIONS]" in results.output
|
||||
assert "--input-dir" in results.output
|
||||
assert "--input-files" in results.output
|
||||
assert "--output-dir" in results.output
|
||||
assert "--verbose" in results.output
|
||||
assert "--version" in results.output
|
||||
assert "from-mail" in results.output
|
||||
assert "from-files" in results.output
|
||||
|
||||
|
||||
def test_version_cli():
|
||||
@@ -162,6 +161,7 @@ def test_cli_input_files_and_input_dir(output_path: Path):
|
||||
results = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"from-files",
|
||||
"--input-files",
|
||||
"a.log",
|
||||
"--input-dir",
|
||||
@@ -183,7 +183,7 @@ def test_cli_neither_input_files_nor_input_dir():
|
||||
Returns:
|
||||
None
|
||||
"""
|
||||
results = runner.invoke(app)
|
||||
results = runner.invoke(app, ["from-files"])
|
||||
assert results.exit_code == 2
|
||||
assert "Either input_files or input_dir must be provided" in results.output
|
||||
|
||||
@@ -205,7 +205,7 @@ def test_cli_bad_input_file(tmp_path: Path, output_path: Path, invalid_log_dir:
|
||||
directory = str(tmp_path)
|
||||
results = runner.invoke(
|
||||
app,
|
||||
["--input-files", directory, "--output-dir", str(output_path)],
|
||||
["from-files", "--input-files", directory, "--output-dir", str(output_path)],
|
||||
)
|
||||
assert results.exit_code == 1
|
||||
assert isinstance(results.exception, ValueError)
|
||||
@@ -231,7 +231,7 @@ def test_cli_empty_input_files(output_path: Path, invalid_log_dir: Path):
|
||||
empty_file = str(next(invalid_log_dir.glob("empty_file.txt")))
|
||||
results = runner.invoke(
|
||||
app,
|
||||
["--input-files", empty_file, "--output-dir", str(output_path)],
|
||||
["from-files", "--input-files", empty_file, "--output-dir", str(output_path)],
|
||||
)
|
||||
assert results.exit_code == 0
|
||||
# check files
|
||||
@@ -288,6 +288,7 @@ def test_cli_input_files_or_input_dir(
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"from-files",
|
||||
"--input-dir",
|
||||
str(original_log_dir),
|
||||
"--output-dir",
|
||||
@@ -310,7 +311,14 @@ def test_cli_input_files_or_input_dir(
|
||||
def test_cli_input_files_one_file(valid_log_dir: Path, output_path: Path):
|
||||
mixed_logs_file = valid_log_dir / "mixed_logs.txt"
|
||||
result = runner.invoke(
|
||||
app, ["--input-files", str(mixed_logs_file), "--output-dir", str(output_path)]
|
||||
app,
|
||||
[
|
||||
"from-files",
|
||||
"--input-files",
|
||||
str(mixed_logs_file),
|
||||
"--output-dir",
|
||||
str(output_path),
|
||||
],
|
||||
)
|
||||
|
||||
assert result.exit_code == 0
|
||||
@@ -345,6 +353,7 @@ def test_cli_empty_input_directory(tmp_path: Path, output_path: Path):
|
||||
result = runner.invoke(
|
||||
app,
|
||||
[
|
||||
"from-files",
|
||||
"--input-dir",
|
||||
str(input_dir),
|
||||
"--output-dir",
|
||||
|
||||
+29
-22
@@ -6,14 +6,15 @@ logwatcher is launched.
|
||||
- the StreamHandler must watch at an error level
|
||||
- the FileHandler must watch at a debug
|
||||
level
|
||||
-
|
||||
-
|
||||
"""
|
||||
|
||||
import logging
|
||||
import re
|
||||
from logging import DEBUG, ERROR, INFO, WARNING, FileHandler, StreamHandler, getLogger
|
||||
|
||||
import pytest
|
||||
|
||||
from logwatcher import logger
|
||||
from logwatcher.logging_config import _setup_formatter, _setup_handler, setup_logging
|
||||
|
||||
|
||||
@@ -22,9 +23,10 @@ def test_setup_handler(tmp_log_file):
|
||||
handler = _setup_handler(formatter=formatter, level=DEBUG)
|
||||
assert isinstance(handler, StreamHandler)
|
||||
|
||||
handler = _setup_handler(formatter=formatter, level=INFO,filename=tmp_log_file)
|
||||
handler = _setup_handler(formatter=formatter, level=INFO, filename=tmp_log_file)
|
||||
assert isinstance(handler, FileHandler)
|
||||
|
||||
|
||||
def test_count_of_handler(tmp_log_file):
|
||||
logger = getLogger()
|
||||
count_file_handler = 0
|
||||
@@ -37,11 +39,13 @@ def test_count_of_handler(tmp_log_file):
|
||||
count_stream_handler += 1
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
assert count_file_handler >= 1
|
||||
assert count_stream_handler >= 1
|
||||
|
||||
|
||||
def test_type_of_handlers():
|
||||
logger = logging.getLogger("logwatcher")
|
||||
for handler in logger.handlers:
|
||||
if isinstance(handler, FileHandler):
|
||||
assert handler.level == DEBUG
|
||||
@@ -49,53 +53,56 @@ def test_type_of_handlers():
|
||||
assert handler.level == ERROR
|
||||
else:
|
||||
pytest.fail("handlers must be either a file or a stream handler")
|
||||
assert handler.formatter._fmt == '[%(asctime)s] - %(levelname)s: %(message)s'
|
||||
assert handler.formatter.datefmt == '%d/%m/%Y %H:%M:%S'
|
||||
assert handler.formatter._fmt == "[%(asctime)s] - %(levelname)s: %(message)s"
|
||||
assert handler.formatter.datefmt == "%d/%m/%Y %H:%M:%S"
|
||||
|
||||
|
||||
def test_modified_format():
|
||||
"""
|
||||
when starting, the logger is first intialized, thus two handlers are at position
|
||||
1 and 2 in logger.handlers list.
|
||||
when starting, the logger is first intialized, thus two handlers are at position
|
||||
1 and 2 in logger.handlers list.
|
||||
"""
|
||||
logger = setup_logging()
|
||||
for handler in logger.handlers[2:]:
|
||||
assert handler.formatter._fmt == '[%(asctime)s] - %(levelname)s: %(message)s'
|
||||
assert handler.formatter._fmt == "[%(asctime)s] - %(levelname)s: %(message)s"
|
||||
|
||||
formatter_different_format = _setup_formatter(format='%(asctime)s - %(levelname)s: %(message)s')
|
||||
formatter_different_format = _setup_formatter(
|
||||
format="%(asctime)s - %(levelname)s: %(message)s"
|
||||
)
|
||||
logger = setup_logging(formatter=formatter_different_format)
|
||||
for handler in logger.handlers[4:]:
|
||||
assert handler.formatter._fmt == '%(asctime)s - %(levelname)s: %(message)s'
|
||||
assert handler.formatter._fmt == "%(asctime)s - %(levelname)s: %(message)s"
|
||||
|
||||
formatter_different_datefmt = _setup_formatter(datefmt='%a %b %Y at %Hh%M')
|
||||
formatter_different_datefmt = _setup_formatter(datefmt="%a %b %Y at %Hh%M")
|
||||
logger = setup_logging(formatter=formatter_different_datefmt)
|
||||
for handler in logger.handlers[6:]:
|
||||
assert handler.formatter._fmt == '[%(asctime)s] - %(levelname)s: %(message)s'
|
||||
assert handler.formatter.datefmt == '%a %b %Y at %Hh%M'
|
||||
assert handler.formatter._fmt == "[%(asctime)s] - %(levelname)s: %(message)s"
|
||||
assert handler.formatter.datefmt == "%a %b %Y at %Hh%M"
|
||||
|
||||
|
||||
def test_logging_in_correct_path(tmp_log_file):
|
||||
logger = logging.getLogger("logwatcher")
|
||||
# must be both in file and stdout
|
||||
logger.critical("hi- BYE")
|
||||
logger.error("hi... ok, bye")
|
||||
logger.warning("hi, are you alright?")
|
||||
|
||||
# only in file
|
||||
logger.info("hi there")
|
||||
logger.debug("hi, how are you? it's been a while!")
|
||||
logger.info("hi there")
|
||||
logger.debug("hi, how are you? it's been a while!")
|
||||
|
||||
with open(tmp_log_file) as log_file:
|
||||
content = log_file.readlines()
|
||||
regex = r'\[\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}\] - '
|
||||
regex = r"\[\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2}\] - "
|
||||
|
||||
assert len(content) == 5
|
||||
for line in content:
|
||||
assert re.search(regex, line)
|
||||
|
||||
# test critical to warning
|
||||
assert re.search(r'CRITICAL: hi- BYE', content[0])
|
||||
assert re.search(r'ERROR: hi... ok, bye', content[1])
|
||||
assert re.search(r'WARNING: hi, are you alright?', content[2])
|
||||
assert re.search(r'INFO: hi there', content[3])
|
||||
assert re.search(r"CRITICAL: hi- BYE", content[0])
|
||||
assert re.search(r"ERROR: hi... ok, bye", content[1])
|
||||
assert re.search(r"WARNING: hi, are you alright?", content[2])
|
||||
assert re.search(r"INFO: hi there", content[3])
|
||||
assert logger.getEffectiveLevel() < WARNING
|
||||
assert re.search(r"DEBUG: hi, how are you\? it's been a while!", content[4])
|
||||
|
||||
+22
-6
@@ -4,7 +4,7 @@ from pathlib import Path
|
||||
import pytest
|
||||
|
||||
from logwatcher.classifier import classify_log_entries
|
||||
from logwatcher.config import DATETIME_FORMAT, FIXTURE_PATH
|
||||
from logwatcher.config import DATETIME_FORMAT, FIXTURE_PATH, SourceType
|
||||
from logwatcher.models import LogEntry
|
||||
from logwatcher.parser import parse_log_file
|
||||
from logwatcher.reporter import (
|
||||
@@ -160,7 +160,12 @@ def test_build_reports(
|
||||
"""The three reports are built with correct headers, counts, and section separation."""
|
||||
start_date, end_date = _get_period(get_all_log_entries[0] + get_all_log_entries[1])
|
||||
reports = build_reports(
|
||||
get_all_log_entries[0], get_all_log_entries[1], start_date, end_date, nb_files
|
||||
SourceType.FILE,
|
||||
get_all_log_entries[0],
|
||||
get_all_log_entries[1],
|
||||
start_date,
|
||||
end_date,
|
||||
nb_files,
|
||||
)
|
||||
|
||||
assert "all" in reports and "n2" in reports and "other" in reports
|
||||
@@ -201,7 +206,7 @@ def _test_write_log_report(
|
||||
"""Write the reports, then verify files exist and their content matches build_reports."""
|
||||
results_path = output_dir / "results"
|
||||
relevant, irrelevant = log_entries_tuple
|
||||
write_log_report(relevant, irrelevant, nb_files, results_path)
|
||||
write_log_report(SourceType.FILE, relevant, irrelevant, nb_files, results_path)
|
||||
# check if files were created
|
||||
all_file, n2_file, other_file = (
|
||||
(results_path / "all.log"),
|
||||
@@ -214,7 +219,9 @@ def _test_write_log_report(
|
||||
|
||||
# check content
|
||||
start_date, end_date = _get_period(relevant + irrelevant)
|
||||
reports = build_reports(relevant, irrelevant, start_date, end_date, nb_files)
|
||||
reports = build_reports(
|
||||
SourceType.FILE, relevant, irrelevant, start_date, end_date, nb_files
|
||||
)
|
||||
nb_errors = {
|
||||
"all": len(relevant + irrelevant),
|
||||
"n2": len(relevant),
|
||||
@@ -271,7 +278,11 @@ def test_write_log_report_all_logs(
|
||||
"""The full fixture writes three files whose content matches build_reports exactly."""
|
||||
results_path = tmp_path / "results"
|
||||
write_log_report(
|
||||
get_all_log_entries[0], get_all_log_entries[1], nb_files, results_path
|
||||
SourceType.FILE,
|
||||
get_all_log_entries[0],
|
||||
get_all_log_entries[1],
|
||||
nb_files,
|
||||
results_path,
|
||||
)
|
||||
|
||||
# check if files were created
|
||||
@@ -287,7 +298,12 @@ def test_write_log_report_all_logs(
|
||||
# check content
|
||||
start_date, end_date = _get_period(get_all_log_entries[0] + get_all_log_entries[1])
|
||||
reports = build_reports(
|
||||
get_all_log_entries[0], get_all_log_entries[1], start_date, end_date, nb_files
|
||||
SourceType.FILE,
|
||||
get_all_log_entries[0],
|
||||
get_all_log_entries[1],
|
||||
start_date,
|
||||
end_date,
|
||||
nb_files,
|
||||
)
|
||||
assert reports["all"] == all_file.read_text(encoding="windows-1252")
|
||||
assert reports["n2"] == n2_file.read_text(encoding="windows-1252")
|
||||
|
||||
Reference in New Issue
Block a user