Skip to content

Commit 217c348

Browse files
author
Vladislav Gogov
authored
Add a scenario test for alter/set compression (#11982)
1 parent f0506e2 commit 217c348

File tree

10 files changed

+692
-48
lines changed

10 files changed

+692
-48
lines changed

ydb/tests/olap/scenario/helpers/data_generators.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
from ydb import PrimitiveType
66
from typing import override, Any, List, Dict
77
import random
8+
import string
89

910

1011
class IColumnValueGenerator(ABC):
@@ -116,6 +117,11 @@ def __init__(self, null_probability: float = 0.5) -> None:
116117
super().__init__()
117118
self._null_propabitity = null_probability
118119

120+
@staticmethod
121+
def random_utf8_string(length):
122+
characters = string.ascii_letters + string.digits + string.punctuation + ' '
123+
return ''.join(random.choices(characters, k=length)).encode('utf-8')
124+
119125
@override
120126
def generate_value(self, column: ScenarioTestHelper.Column) -> Any:
121127
if not column.not_null and random.random() <= self._null_propabitity:
@@ -140,8 +146,10 @@ def generate_value(self, column: ScenarioTestHelper.Column) -> Any:
140146
return random.randint(0, 2**64 - 1)
141147
elif column.type in {PrimitiveType.Float, PrimitiveType.Double}:
142148
return random.uniform(-1e6, 1e6)
143-
elif column.type in {PrimitiveType.String, PrimitiveType.Utf8}:
149+
elif column.type == PrimitiveType.String:
144150
return random.randbytes(15)
151+
elif column.type == PrimitiveType.Utf8:
152+
return self.random_utf8_string(15)
145153
elif column.type in {PrimitiveType.Json, PrimitiveType.JsonDocument}:
146154
return f'"{random.randbytes(15)}"'
147155
elif column.type == PrimitiveType.Timestamp:

ydb/tests/olap/scenario/helpers/scenario_tests_helper.py

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
from __future__ import annotations
2+
import enum
23
import os
34
import allure
45
import allure_commons
@@ -67,26 +68,72 @@ class ScenarioTestHelper:
6768
ydb.StatusCode.UNAVAILABLE,
6869
}
6970

71+
@enum.unique
72+
class Compression(enum.IntEnum):
73+
OFF = 1
74+
LZ4 = 2
75+
ZSTD = 3
76+
77+
class ColumnFamily:
78+
"""A class that describes a column family."""
79+
80+
def __init__(self, name: str, compression: ScenarioTestHelper.Compression, compression_level: Optional[int]):
81+
"""Constructor.
82+
83+
Args:
84+
name: Column family name.
85+
compression: Compression codec.
86+
compression_level: Compression codec level.
87+
"""
88+
89+
self._name = name
90+
self._compression = compression
91+
self._compression_level = compression_level
92+
93+
def to_yql(self) -> str:
94+
"""Convert to YQL"""
95+
return f'FAMILY {self._name} (COMPRESSION = "{self._compression.name}"{", COMPRESSION_LEVEL = " + str(self._compression_level) if self._compression_level is not None else ""})'
96+
97+
@property
98+
def name(self) -> str:
99+
"""Column family name."""
100+
101+
return self._name
102+
103+
@property
104+
def compression(self) -> ScenarioTestHelper.Compression:
105+
"""Compression"""
106+
107+
return self._compression
108+
109+
@property
110+
def compression_level(self) -> Optional[int]:
111+
"""Compression level."""
112+
113+
return self._compression_level
114+
70115
class Column:
71116
"""A class that describes a table column."""
72117

73-
def __init__(self, name: str, type: ydb.PrimitiveType, not_null: bool = False) -> None:
118+
def __init__(self, name: str, type: ydb.PrimitiveType, column_family_name: str = "", not_null: bool = False) -> None:
74119
"""Constructor.
75120
76121
Args:
77122
name: Column name.
78123
type: Column type.
124+
column_family_name: Column Family name.
79125
not_null: Whether the entry in the column can be NULL.
80126
"""
81127

82128
self._name = name
83129
self._type = type
130+
self._column_family_name = column_family_name
84131
self._not_null = not_null
85132

86133
def to_yql(self) -> str:
87134
"""Convert to YQL"""
88135

89-
return f'{self._name} {self._type}{" NOT NULL" if self._not_null else ""}'
136+
return f'{self._name} {self._type}{"" if not self._column_family_name else f" FAMILY {self._column_family_name}"}{" NOT NULL" if self._not_null else ""}'
90137

91138
@property
92139
def bulk_upsert_type(self) -> ydb.OptionalType | ydb.PrimitiveType:
@@ -108,6 +155,11 @@ def type(self) -> ydb.PrimitiveType:
108155

109156
return self._type
110157

158+
def column_family(self) -> str:
159+
"""Colum family name"""
160+
161+
return "default" if not self._column_family_name else self._column_family_name
162+
111163
@property
112164
def not_null(self) -> bool:
113165
"""Whether the entry in the column can be NULL."""
@@ -121,8 +173,9 @@ class Schema:
121173
schema = (
122174
ScenarioTestHelper.Schema()
123175
.with_column(name='id', type=PrimitiveType.Int32, not_null=True)
124-
.with_column(name='level', type=PrimitiveType.Uint32)
176+
.with_column(name='level', type=PrimitiveType.Uint32, column_family_name="family1")
125177
.with_key_columns('id')
178+
.with_column_family(name="family1", compression=ScenarioTestHelper.Compression.LZ4, compression_level=None)
126179
)
127180
"""
128181

@@ -131,6 +184,7 @@ def __init__(self) -> None:
131184

132185
self.columns = []
133186
self.key_columns = []
187+
self.column_families = []
134188

135189
def with_column(self, *vargs, **kargs) -> ScenarioTestHelper.Schema:
136190
"""Add a column.
@@ -156,6 +210,18 @@ def with_key_columns(self, *vargs: str) -> ScenarioTestHelper.Schema:
156210
self.key_columns += vargs
157211
return self
158212

213+
def with_column_family(self, *vargs, **kargs) -> ScenarioTestHelper.Schema:
214+
"""Add a column family.
215+
216+
The method arguments are the same as {ScenarioTestHelper.ColumnFamily.__init__}.
217+
218+
Returns:
219+
self.
220+
"""
221+
222+
self.column_families.append(ScenarioTestHelper.ColumnFamily(*vargs, **kargs))
223+
return self
224+
159225
def build_bulk_columns_types(self) -> ydb.BulkUpsertColumns:
160226
"""Convert to ydb.BulkUpsertColumns"""
161227

@@ -643,3 +709,15 @@ def remove_path(self, path: str) -> None:
643709
)
644710
else:
645711
pytest.fail(f'Cannot remove type {repr(e.type)} for path {os.path.join(root_path, e.name)}')
712+
713+
def get_volumes_columns(self, table_name: str, name_column: str) -> tuple[int, int]:
714+
query = f'''SELECT * FROM `{ScenarioTestHelper(self.test_context).get_full_path(table_name)}/.sys/primary_index_stats` WHERE Activity == 1'''
715+
if (len(name_column)):
716+
query += f' AND EntityName = \"{name_column}\"'
717+
result_set = self.execute_scan_query(query, {ydb.StatusCode.SUCCESS}).result_set
718+
raw_bytes = 0
719+
bytes = 0
720+
for row in result_set.rows:
721+
raw_bytes += row["RawBytes"]
722+
bytes += row["BlobRangeSize"]
723+
return raw_bytes, bytes

0 commit comments

Comments
 (0)