Skip to content

Commit 205ca10

Browse files
Tests for PostgresNodeLogReader._create_log_info are added
1 parent e62d547 commit 205ca10

3 files changed

Lines changed: 107 additions & 6 deletions

File tree

src/node.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2593,23 +2593,28 @@ def _collect_logs(self, find_line_start: bool) -> typing.Dict[str, LogInfo]:
25932593
if not self._node.os_ops.path_exists(f):
25942594
continue
25952595

2596-
result[f] = self._create_log_info(f, find_line_start)
2596+
result[f] = self._create_log_info(
2597+
self._node.os_ops,
2598+
f,
2599+
find_line_start,
2600+
)
25972601
continue
25982602

25992603
return result
26002604

2605+
@staticmethod
26012606
def _create_log_info(
2602-
self,
2607+
os_ops: OsOperations,
26032608
filename: str,
26042609
find_line_start: bool,
26052610
) -> LogInfo:
26062611
assert type(filename) is str
26072612
assert type(find_line_start) is bool
26082613
assert len(filename) > 0
2609-
assert self._node is not None
2610-
assert isinstance(self._node, PostgresNode)
2614+
assert os_ops is not None
2615+
assert isinstance(os_ops, OsOperations)
26112616

2612-
file_size = self._node.os_ops.get_file_size(filename)
2617+
file_size = os_ops.get_file_size(filename)
26132618
assert type(file_size) is int
26142619
assert file_size >= 0
26152620

@@ -2642,7 +2647,7 @@ def _create_log_info(
26422647

26432648
# read from read_offset to file end
26442649
# TODO: improve it when os_ops_will support size in read_binary operation
2645-
tail = self._node.os_ops.read_binary(filename, read_offset)
2650+
tail = os_ops.read_binary(filename, read_offset)
26462651

26472652
assert type(tail) is bytes
26482653

tests/units/node/PostgresNodeLogReader/__init__.py

Whitespace-only changes.
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
from __future__ import annotations
2+
3+
from ....helpers.global_data import OsOpsDescrs
4+
from ....helpers.global_data import OsOpsDescr
5+
from ....helpers.global_data import OsOperations
6+
7+
from src.node import PostgresNodeLogReader
8+
9+
import pytest
10+
import typing
11+
import random
12+
13+
14+
class TestSetM001__helper_create_log_info:
15+
sm_os_ops_descrs: typing.List[OsOpsDescr] = [
16+
OsOpsDescrs.sm_local_os_ops_descr,
17+
OsOpsDescrs.sm_remote_os_ops_descr
18+
]
19+
20+
@pytest.fixture(
21+
params=[
22+
pytest.param(
23+
descr,
24+
id=descr.sign,
25+
)
26+
for descr in sm_os_ops_descrs
27+
],
28+
)
29+
def os_ops_descr(self, request: pytest.FixtureRequest) -> OsOpsDescr:
30+
assert isinstance(request, pytest.FixtureRequest)
31+
assert isinstance(request.param, OsOpsDescr)
32+
return request.param
33+
34+
def test_001__common(self, os_ops_descr: OsOpsDescr):
35+
assert type(os_ops_descr) is OsOpsDescr
36+
os_ops = os_ops_descr.os_ops
37+
assert isinstance(os_ops, OsOperations)
38+
39+
# Scenario 1: The log file ends with a normal line feed
40+
filename = os_ops.mkstemp("data_for_create_log_info")
41+
C_DATA1 = b"Line 1\nLine 2\n"
42+
os_ops.write(filename, C_DATA1, binary=True, truncate=True)
43+
44+
log_info1 = PostgresNodeLogReader._create_log_info(os_ops, filename, find_line_start=True)
45+
# Since the file ends with \n, the tail must be empty!
46+
assert log_info1.tail == b""
47+
assert log_info1.position == len(C_DATA1)
48+
49+
# Scenario 2: The log file contains an unterminated line (our UTF-8 trap)
50+
C_DATA2 = b"Line 1\nLine 2\nIncomplete UTF8 \xd0"
51+
os_ops.write(filename, C_DATA2, binary=True, truncate=True)
52+
53+
log_info2 = PostgresNodeLogReader._create_log_info(os_ops, filename, find_line_start=True)
54+
# The tail must contain exactly the piece after the last \n
55+
assert log_info2.tail == b"Incomplete UTF8 \xd0"
56+
assert log_info2.position == len(C_DATA2)
57+
58+
# Scenario 3: The file has no line breaks at all (one long line)
59+
C_DATA3 = b"Just one long line without newlines"
60+
os_ops.write(filename, C_DATA3, binary=True, truncate=True)
61+
62+
log_info3 = PostgresNodeLogReader._create_log_info(os_ops, filename, find_line_start=True)
63+
# Should take the entire file in tail, and set the position to the file size
64+
assert log_info3.tail == b"Just one long line without newlines"
65+
assert log_info3.position == len(C_DATA3)
66+
67+
# 4. Large data (two segments)
68+
allowed_bytes = bytes([b for b in range(256) if b != 10])
69+
C_DATA4 = bytes(random.choices(allowed_bytes, k=5000))
70+
os_ops.write(filename, C_DATA4, binary=True, truncate=True)
71+
72+
log_info = PostgresNodeLogReader._create_log_info(os_ops, filename, find_line_start=True)
73+
assert log_info.tail == C_DATA4
74+
assert log_info.position == len(C_DATA4)
75+
76+
# 5. Large data (many segments)
77+
allowed_bytes = bytes([b for b in range(256) if b != 10])
78+
C_DATA5 = bytes(random.choices(allowed_bytes, k=999983))
79+
os_ops.write(filename, C_DATA5, binary=True, truncate=True)
80+
81+
log_info = PostgresNodeLogReader._create_log_info(os_ops, filename, find_line_start=True)
82+
assert log_info.tail == C_DATA5
83+
assert log_info.position == len(C_DATA5)
84+
85+
# 6. Large data (first_line + many segments)
86+
allowed_bytes = bytes([b for b in range(256) if b != 10])
87+
os_ops.write(filename, b'abcd\n', binary=True, truncate=True)
88+
os_ops.write(filename, C_DATA5, binary=True, truncate=False)
89+
90+
log_info = PostgresNodeLogReader._create_log_info(os_ops, filename, find_line_start=True)
91+
assert log_info.tail == C_DATA5
92+
assert log_info.position == 5 + len(C_DATA5)
93+
94+
# Cleanup
95+
os_ops.remove_file(filename)
96+
return

0 commit comments

Comments
 (0)