From 591613bfe8b5df2b5c48653ea8dcc31ecd3d8dff Mon Sep 17 00:00:00 2001 From: Daniil Timizhev Date: Wed, 8 Oct 2025 13:54:42 +0300 Subject: [PATCH 1/4] More serverless with TestCreateServerLessDb --- .../ut_column_build/ut_column_build.cpp | 421 +++++------------- 1 file changed, 112 insertions(+), 309 deletions(-) diff --git a/ydb/core/tx/schemeshard/ut_column_build/ut_column_build.cpp b/ydb/core/tx/schemeshard/ut_column_build/ut_column_build.cpp index b3618a989bb8..7be3a28c5bff 100644 --- a/ydb/core/tx/schemeshard/ut_column_build/ut_column_build.cpp +++ b/ydb/core/tx/schemeshard/ut_column_build/ut_column_build.cpp @@ -13,68 +13,10 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { TTestBasicRuntime runtime; TTestEnv env(runtime, TTestEnvOptions().EnableAddColumsWithDefaults(true)); ui64 txId = 100; - - TestCreateExtSubDomain(runtime, ++txId, "/MyRoot", - "Name: \"ResourceDB\""); - env.TestWaitNotification(runtime, txId); - - const auto describeResult = DescribePath(runtime, "/MyRoot/ResourceDB"); - const auto subDomainPathId = describeResult.GetPathId(); - - TestAlterExtSubDomain(runtime, ++txId, "/MyRoot", - "StoragePools { " - " Name: \"pool-1\" " - " Kind: \"pool-kind-1\" " - "} " - "StoragePools { " - " Name: \"pool-2\" " - " Kind: \"pool-kind-2\" " - "} " - "PlanResolution: 50 " - "Coordinators: 1 " - "Mediators: 1 " - "TimeCastBucketsPerMediator: 2 " - "ExternalSchemeShard: true " - "Name: \"ResourceDB\""); - env.TestWaitNotification(runtime, txId); - - const auto attrs = AlterUserAttrs({ - {"cloud_id", "CLOUD_ID_VAL"}, - {"folder_id", "FOLDER_ID_VAL"}, - {"database_id", "DATABASE_ID_VAL"} - }); - - TestCreateExtSubDomain(runtime, ++txId, "/MyRoot", Sprintf(R"( - Name: "ServerLessDB" - ResourcesDomainKey { - SchemeShard: %lu - PathId: %lu - } - )", TTestTxConfig::SchemeShard, subDomainPathId), attrs); - env.TestWaitNotification(runtime, txId); - - TString alterData = TStringBuilder() - << "PlanResolution: 50 " - << "Coordinators: 1 " - << "Mediators: 1 " - << "TimeCastBucketsPerMediator: 2 " - << "ExternalSchemeShard: true " - << "ExternalHive: false " - << "Name: \"ServerLessDB\" " - << "StoragePools { " - << " Name: \"pool-1\" " - << " Kind: \"pool-kind-1\" " - << "} "; - TestAlterExtSubDomain(runtime, ++txId, "/MyRoot", alterData); - env.TestWaitNotification(runtime, txId); - ui64 tenantSchemeShard = 0; - TestDescribeResult(DescribePath(runtime, "/MyRoot/ServerLessDB"), - {NLs::PathExist, - NLs::IsExternalSubDomain("ServerLessDB"), - NLs::ExtractTenantSchemeshard(&tenantSchemeShard)}); - // Just create main table + TestCreateServerLessDb(runtime, env, txId, tenantSchemeShard); + TestCreateTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB", R"( Name: "Table" Columns { Name: "key" Type: "Uint32" } @@ -96,94 +38,43 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { TString err; NKikimrProto::EReplyStatus status = LocalMiniKQL(runtime, tabletId, writeQuery, result, err); UNIT_ASSERT_VALUES_EQUAL(err, ""); - UNIT_ASSERT_VALUES_EQUAL(status, NKikimrProto::EReplyStatus::OK);; + UNIT_ASSERT_VALUES_EQUAL(status, NKikimrProto::EReplyStatus::OK); }; for (ui32 delta = 0; delta < 101; ++delta) { fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, 1 + delta, 1000 + delta, "aaaa", "Table"); } + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), + {NLs::PathExist, + NLs::IndexesCount(0), + NLs::PathVersionEqual(3), + NLs::CheckColumns("Table", {"key", "index", "value"}, {}, {"key"})}); + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + const TString columnName = "value"; + Ydb::TypedValue columnDefaultValue; + columnDefaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); + columnDefaultValue.mutable_value()->set_uint64_value(10); + + TestBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", columnName, columnDefaultValue, Ydb::StatusIds::BAD_REQUEST); + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), {NLs::PathExist, NLs::IndexesCount(0), - NLs::PathVersionEqual(3)}); - - Ydb::TypedValue defaultValue; - defaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); - defaultValue.mutable_value()->set_uint64_value(10); - - TestBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "value", defaultValue, Ydb::StatusIds::BAD_REQUEST); + NLs::PathVersionEqual(3), + NLs::CheckColumns("Table", {"key", "index", "value"}, {}, {"key"})}); } - // TODO: rename to InvalidValue and check invalid default value Y_UNIT_TEST(ValidDefaultValue) { TTestBasicRuntime runtime; TTestEnv env(runtime, TTestEnvOptions().EnableAddColumsWithDefaults(true)); ui64 txId = 100; - - TestCreateExtSubDomain(runtime, ++txId, "/MyRoot", - "Name: \"ResourceDB\""); - env.TestWaitNotification(runtime, txId); - - const auto describeResult = DescribePath(runtime, "/MyRoot/ResourceDB"); - const auto subDomainPathId = describeResult.GetPathId(); - - TestAlterExtSubDomain(runtime, ++txId, "/MyRoot", - "StoragePools { " - " Name: \"pool-1\" " - " Kind: \"pool-kind-1\" " - "} " - "StoragePools { " - " Name: \"pool-2\" " - " Kind: \"pool-kind-2\" " - "} " - "PlanResolution: 50 " - "Coordinators: 1 " - "Mediators: 1 " - "TimeCastBucketsPerMediator: 2 " - "ExternalSchemeShard: true " - "Name: \"ResourceDB\""); - env.TestWaitNotification(runtime, txId); - - const auto attrs = AlterUserAttrs({ - {"cloud_id", "CLOUD_ID_VAL"}, - {"folder_id", "FOLDER_ID_VAL"}, - {"database_id", "DATABASE_ID_VAL"} - }); - - TestCreateExtSubDomain(runtime, ++txId, "/MyRoot", Sprintf(R"( - Name: "ServerLessDB" - ResourcesDomainKey { - SchemeShard: %lu - PathId: %lu - } - )", TTestTxConfig::SchemeShard, subDomainPathId), attrs); - env.TestWaitNotification(runtime, txId); - - TString alterData = TStringBuilder() - << "PlanResolution: 50 " - << "Coordinators: 1 " - << "Mediators: 1 " - << "TimeCastBucketsPerMediator: 2 " - << "ExternalSchemeShard: true " - << "ExternalHive: false " - << "Name: \"ServerLessDB\" " - << "StoragePools { " - << " Name: \"pool-1\" " - << " Kind: \"pool-kind-1\" " - << "} "; - TestAlterExtSubDomain(runtime, ++txId, "/MyRoot", alterData); - env.TestWaitNotification(runtime, txId); - ui64 tenantSchemeShard = 0; - TestDescribeResult(DescribePath(runtime, "/MyRoot/ServerLessDB"), - {NLs::PathExist, - NLs::IsExternalSubDomain("ServerLessDB"), - NLs::ExtractTenantSchemeshard(&tenantSchemeShard)}); - // Just create main table + TestCreateServerLessDb(runtime, env, txId, tenantSchemeShard); + TestCreateTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB", R"( Name: "Table" Columns { Name: "key" Type: "Uint32" } @@ -205,25 +96,27 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { TString err; NKikimrProto::EReplyStatus status = LocalMiniKQL(runtime, tabletId, writeQuery, result, err); UNIT_ASSERT_VALUES_EQUAL(err, ""); - UNIT_ASSERT_VALUES_EQUAL(status, NKikimrProto::EReplyStatus::OK);; + UNIT_ASSERT_VALUES_EQUAL(status, NKikimrProto::EReplyStatus::OK); }; for (ui32 delta = 0; delta < 101; ++delta) { fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, 1 + delta, 1000 + delta, "aaaa", "Table"); } - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); - runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); - TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), {NLs::PathExist, NLs::IndexesCount(0), - NLs::PathVersionEqual(3)}); + NLs::PathVersionEqual(3), + NLs::CheckColumns("Table", {"key", "index", "value"}, {}, {"key"})}); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); - Ydb::TypedValue defaultValue; - defaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); - defaultValue.mutable_value()->set_uint64_value(1111); // TODO: check invalid value + const TString columnName = "ColumnValue"; + Ydb::TypedValue columnDefaultValue; + columnDefaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); + columnDefaultValue.mutable_value()->set_uint64_value(1111); - TestBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "ColumnValue", defaultValue, Ydb::StatusIds::SUCCESS); + TestBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", columnName, columnDefaultValue, Ydb::StatusIds::SUCCESS); auto listing = TestListBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB"); Y_ASSERT(listing.EntriesSize() == 1); @@ -232,74 +125,22 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { auto descr = TestGetBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB", txId); Y_ASSERT(descr.GetIndexBuild().GetState() == Ydb::Table::IndexBuildState::STATE_DONE); + + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), + {NLs::PathExist, + NLs::IndexesCount(0), + NLs::PathVersionEqual(6), + NLs::CheckColumns("Table", {"key", "index", "value", columnName}, {}, {"key"})}); } Y_UNIT_TEST(BuildColumnDoesnotRestoreDeletedRows) { TTestBasicRuntime runtime(1, false); TTestEnv env(runtime, TTestEnvOptions().EnableAddColumsWithDefaults(true)); ui64 txId = 100; - - TestCreateExtSubDomain(runtime, ++txId, "/MyRoot", - "Name: \"ResourceDB\""); - env.TestWaitNotification(runtime, txId); - - const auto describeResult = DescribePath(runtime, "/MyRoot/ResourceDB"); - const auto subDomainPathId = describeResult.GetPathId(); - - TestAlterExtSubDomain(runtime, ++txId, "/MyRoot", - "StoragePools { " - " Name: \"pool-1\" " - " Kind: \"pool-kind-1\" " - "} " - "StoragePools { " - " Name: \"pool-2\" " - " Kind: \"pool-kind-2\" " - "} " - "PlanResolution: 50 " - "Coordinators: 1 " - "Mediators: 1 " - "TimeCastBucketsPerMediator: 2 " - "ExternalSchemeShard: true " - "Name: \"ResourceDB\""); - env.TestWaitNotification(runtime, txId); - - const auto attrs = AlterUserAttrs({ - {"cloud_id", "CLOUD_ID_VAL"}, - {"folder_id", "FOLDER_ID_VAL"}, - {"database_id", "DATABASE_ID_VAL"} - }); - - TestCreateExtSubDomain(runtime, ++txId, "/MyRoot", Sprintf(R"( - Name: "ServerLessDB" - ResourcesDomainKey { - SchemeShard: %lu - PathId: %lu - } - )", TTestTxConfig::SchemeShard, subDomainPathId), attrs); - env.TestWaitNotification(runtime, txId); - - TString alterData = TStringBuilder() - << "PlanResolution: 50 " - << "Coordinators: 1 " - << "Mediators: 1 " - << "TimeCastBucketsPerMediator: 2 " - << "ExternalSchemeShard: true " - << "ExternalHive: false " - << "Name: \"ServerLessDB\" " - << "StoragePools { " - << " Name: \"pool-1\" " - << " Kind: \"pool-kind-1\" " - << "} "; - TestAlterExtSubDomain(runtime, ++txId, "/MyRoot", alterData); - env.TestWaitNotification(runtime, txId); - ui64 tenantSchemeShard = 0; - TestDescribeResult(DescribePath(runtime, "/MyRoot/ServerLessDB"), - {NLs::PathExist, - NLs::IsExternalSubDomain("ServerLessDB"), - NLs::ExtractTenantSchemeshard(&tenantSchemeShard)}); - // Just create main table + TestCreateServerLessDb(runtime, env, txId, tenantSchemeShard); + TestCreateTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB", R"( Name: "Table" Columns { Name: "key" Type: "Uint64" } @@ -342,13 +183,14 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, 1 + delta, 1000 + delta, "aaaa", "Table"); } - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); - runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); - TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), {NLs::PathExist, NLs::IndexesCount(0), - NLs::PathVersionEqual(3)}); + NLs::PathVersionEqual(3), + NLs::CheckColumns("Table", {"key", "index", "value"}, {}, {"key"})}); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); TStringBuilder meteringMessages; @@ -370,11 +212,12 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { runtime.SetObserverFunc(grab); - Ydb::TypedValue defaultValue; - defaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); - defaultValue.mutable_value()->set_uint64_value(10); + const TString columnName = "DefaultValue"; + Ydb::TypedValue columnDefaultValue; + columnDefaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); + columnDefaultValue.mutable_value()->set_uint64_value(10); - AsyncBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "DefaultValue", defaultValue); + AsyncBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", columnName, columnDefaultValue); runtime.DispatchEvents(opts); Cerr << delayedUpsertRows.size() << Endl; @@ -398,6 +241,12 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { auto descr = TestGetBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB", txId); Y_ASSERT(descr.GetIndexBuild().GetState() == Ydb::Table::IndexBuildState::STATE_DONE); + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), + {NLs::PathExist, + NLs::IndexesCount(0), + NLs::PathVersionEqual(6), + NLs::CheckColumns("Table", {"key", "index", "value", columnName}, {}, {"key"})}); + for (ui32 delta = 50; delta < 101; ++delta) { UNIT_ASSERT(CheckLocalRowExists(runtime, TTestTxConfig::FakeHiveTablets + 6, "__user__Table", "key", 1 + delta)); } @@ -411,68 +260,10 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { TTestBasicRuntime runtime; TTestEnv env(runtime, TTestEnvOptions().EnableAddColumsWithDefaults(true)); ui64 txId = 100; - - TestCreateExtSubDomain(runtime, ++txId, "/MyRoot", - "Name: \"ResourceDB\""); - env.TestWaitNotification(runtime, txId); - - const auto describeResult = DescribePath(runtime, "/MyRoot/ResourceDB"); - const auto subDomainPathId = describeResult.GetPathId(); - - TestAlterExtSubDomain(runtime, ++txId, "/MyRoot", - "StoragePools { " - " Name: \"pool-1\" " - " Kind: \"pool-kind-1\" " - "} " - "StoragePools { " - " Name: \"pool-2\" " - " Kind: \"pool-kind-2\" " - "} " - "PlanResolution: 50 " - "Coordinators: 1 " - "Mediators: 1 " - "TimeCastBucketsPerMediator: 2 " - "ExternalSchemeShard: true " - "Name: \"ResourceDB\""); - env.TestWaitNotification(runtime, txId); - - const auto attrs = AlterUserAttrs({ - {"cloud_id", "CLOUD_ID_VAL"}, - {"folder_id", "FOLDER_ID_VAL"}, - {"database_id", "DATABASE_ID_VAL"} - }); - - TestCreateExtSubDomain(runtime, ++txId, "/MyRoot", Sprintf(R"( - Name: "ServerLessDB" - ResourcesDomainKey { - SchemeShard: %lu - PathId: %lu - } - )", TTestTxConfig::SchemeShard, subDomainPathId), attrs); - env.TestWaitNotification(runtime, txId); - - TString alterData = TStringBuilder() - << "PlanResolution: 50 " - << "Coordinators: 1 " - << "Mediators: 1 " - << "TimeCastBucketsPerMediator: 2 " - << "ExternalSchemeShard: true " - << "ExternalHive: false " - << "Name: \"ServerLessDB\" " - << "StoragePools { " - << " Name: \"pool-1\" " - << " Kind: \"pool-kind-1\" " - << "} "; - TestAlterExtSubDomain(runtime, ++txId, "/MyRoot", alterData); - env.TestWaitNotification(runtime, txId); - ui64 tenantSchemeShard = 0; - TestDescribeResult(DescribePath(runtime, "/MyRoot/ServerLessDB"), - {NLs::PathExist, - NLs::IsExternalSubDomain("ServerLessDB"), - NLs::ExtractTenantSchemeshard(&tenantSchemeShard)}); - // Just create main table + TestCreateServerLessDb(runtime, env, txId, tenantSchemeShard); + TestCreateTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB", R"( Name: "Table" Columns { Name: "key" Type: "Uint32" } @@ -500,13 +291,14 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, 1 + delta, 1000 + delta, "aaaa", "Table"); } - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); - runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); - TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), {NLs::PathExist, NLs::IndexesCount(0), - NLs::PathVersionEqual(3)}); + NLs::PathVersionEqual(3), + NLs::CheckColumns("Table", {"key", "index", "value"}, {}, {"key"})}); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); TStringBuilder meteringMessages; auto grabMeteringMessage = [&meteringMessages](TAutoPtr& ev) -> auto { @@ -521,11 +313,12 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { runtime.SetObserverFunc(grabMeteringMessage); - Ydb::TypedValue defaultValue; - defaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); - defaultValue.mutable_value()->set_uint64_value(10); + const TString columnName = "DefaultValue"; + Ydb::TypedValue columnDefaultValue; + columnDefaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); + columnDefaultValue.mutable_value()->set_uint64_value(10); - TestBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", "DefaultValue", defaultValue, Ydb::StatusIds::SUCCESS); + TestBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", columnName, columnDefaultValue, Ydb::StatusIds::SUCCESS); // ui64 buildIndexId = txId; auto listing = TestListBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB"); @@ -540,7 +333,7 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { {NLs::PathExist, NLs::IndexesCount(0), NLs::PathVersionEqual(6), - NLs::CheckColumns("Table", {"key", "index", "value", "DefaultValue"}, {}, {"key"})}); + NLs::CheckColumns("Table", {"key", "index", "value", columnName}, {}, {"key"})}); /* const TString meteringData = R"({"usage":{"start":0,"quantity":179,"finish":0,"unit":"request_unit","type":"delta"},"tags":{},"id":"106-72075186233409549-2-101-1818-101-1818","cloud_id":"CLOUD_ID_VAL","source_wt":0,"source_id":"sless-docapi-ydb-ss","resource_id":"DATABASE_ID_VAL","schema":"ydb.serverless.requests.v1","folder_id":"FOLDER_ID_VAL","version":"1.0.0"})"; @@ -565,9 +358,11 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { TTestBasicRuntime runtime; TTestEnv env(runtime, TTestEnvOptions().EnableAddColumsWithDefaults(true)); ui64 txId = 100; + ui64 tenantSchemeShard = 0; - // Just create main table - TestCreateTable(runtime, ++txId, "/MyRoot", R"( + TestCreateServerLessDb(runtime, env, txId, tenantSchemeShard); + + TestCreateTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB", R"( Name: "Table" Columns { Name: "key" Type: "Uint32" } Columns { Name: "index" Type: "Uint32" } @@ -575,7 +370,7 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { KeyColumnNames: ["key"] UniformPartitionsCount: 10 )"); - env.TestWaitNotification(runtime, txId); + env.TestWaitNotification(runtime, txId, tenantSchemeShard); auto fnWriteRow = [&] (ui64 tabletId, ui32 key, ui32 index, TString value, const char* table) { TString writeQuery = Sprintf(R"( @@ -592,39 +387,41 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { UNIT_ASSERT_VALUES_EQUAL(status, NKikimrProto::EReplyStatus::OK);; }; for (ui32 delta = 0; delta < 101; ++delta) { - fnWriteRow(TTestTxConfig::FakeHiveTablets, 1 + delta, 1000 + delta, "aaaa", "Table"); + fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, 1 + delta, 1000 + delta, "aaaa", "Table"); } - runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); - - TestDescribeResult(DescribePath(runtime, "/MyRoot/Table"), + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), {NLs::PathExist, NLs::IndexesCount(0), - NLs::PathVersionEqual(3)}); + NLs::PathVersionEqual(3), + NLs::CheckColumns("Table", {"key", "index", "value"}, {}, {"key"})}); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); - Ydb::TypedValue defaultValue; - defaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); - defaultValue.mutable_value()->set_uint64_value(10); + const TString columnName = "DefaultValue"; + Ydb::TypedValue columnDefaultValue; + columnDefaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); + columnDefaultValue.mutable_value()->set_uint64_value(10); - TestBuildColumn(runtime, ++txId, TTestTxConfig::SchemeShard, "/MyRoot", "/MyRoot/Table", "DefaultValue", defaultValue, Ydb::StatusIds::SUCCESS); + TestBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", columnName, columnDefaultValue, Ydb::StatusIds::SUCCESS); ui64 buildIndexId = txId; - auto listing = TestListBuildIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot"); + auto listing = TestListBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB"); Y_ASSERT(listing.EntriesSize() == 1); - TestCancelBuildIndex(runtime, ++txId, TTestTxConfig::SchemeShard, "/MyRoot", buildIndexId); + TestCancelBuildIndex(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", buildIndexId); + env.TestWaitNotification(runtime, buildIndexId, tenantSchemeShard); - env.TestWaitNotification(runtime, buildIndexId); - - auto descr = TestGetBuildIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot", buildIndexId); + auto descr = TestGetBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB", buildIndexId); Y_ASSERT(descr.GetIndexBuild().GetState() == Ydb::Table::IndexBuildState::STATE_CANCELLED); - TestDescribeResult(DescribePath(runtime, "/MyRoot/Table"), + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), {NLs::PathExist, NLs::IndexesCount(0), NLs::PathVersionEqual(7), - NLs::CheckColumns("Table", {"key", "index", "value"}, {"DefaultValue"}, {"key"})}); + NLs::CheckColumns("Table", {"key", "index", "value"}, {columnName}, {"key"})}); } // Test with invalid default value @@ -632,15 +429,18 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { TTestBasicRuntime runtime; TTestEnv env(runtime, TTestEnvOptions().EnableAddColumsWithDefaults(true)); ui64 txId = 100; + ui64 tenantSchemeShard = 0; - TestCreateTable(runtime, ++txId, "/MyRoot", R"( + TestCreateServerLessDb(runtime, env, txId, tenantSchemeShard); + + TestCreateTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB", R"( Name: "Table" Columns { Name: "key" Type: "Uint32" } Columns { Name: "value" Type: "Utf8" } KeyColumnNames: ["key"] UniformPartitionsCount: 10 )"); - env.TestWaitNotification(runtime, txId); + env.TestWaitNotification(runtime, txId, tenantSchemeShard); auto fnWriteRow = [&] (ui64 tabletId, ui32 key, TString value, const char* table) { TString writeQuery = Sprintf(R"( @@ -659,34 +459,37 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { }; for (ui32 delta = 0; delta < 101; ++delta) { - fnWriteRow(TTestTxConfig::FakeHiveTablets, 1 + delta, "abcd", "Table"); + fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, 1 + delta, "abcd", "Table"); } - TestDescribeResult(DescribePath(runtime, "/MyRoot/Table"), + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), {NLs::PathExist, NLs::IndexesCount(0), - NLs::PathVersionEqual(3)}); + NLs::PathVersionEqual(3), + NLs::CheckColumns("Table", {"key", "value"}, {}, {"key"})}); - Ydb::TypedValue defaultValue; - defaultValue.mutable_type()->set_type_id(Ydb::Type::JSON); - defaultValue.mutable_value()->set_text_value("{not json]"); + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); - TestBuildColumn(runtime, ++txId, TTestTxConfig::SchemeShard, "/MyRoot", "/MyRoot/Table", "DefaultValue", defaultValue, Ydb::StatusIds::SUCCESS); + const TString columnName = "DefaultValue"; + Ydb::TypedValue columnDefaultValue; + columnDefaultValue.mutable_type()->set_type_id(Ydb::Type::JSON); + columnDefaultValue.mutable_value()->set_text_value("{not json]"); - ui64 buildIndexId = txId; + TestBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", columnName, columnDefaultValue, Ydb::StatusIds::SUCCESS); - auto listing = TestListBuildIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot"); + auto listing = TestListBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB"); Y_ASSERT(listing.EntriesSize() == 1); - env.TestWaitNotification(runtime, buildIndexId); + env.TestWaitNotification(runtime, txId, tenantSchemeShard); - auto descr = TestGetBuildIndex(runtime, TTestTxConfig::SchemeShard, "/MyRoot", buildIndexId); + auto descr = TestGetBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB", txId); Y_ASSERT(descr.GetIndexBuild().GetState() == Ydb::Table::IndexBuildState::STATE_REJECTED); - TestDescribeResult(DescribePath(runtime, "/MyRoot/Table"), + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), {NLs::PathExist, NLs::IndexesCount(0), NLs::PathVersionEqual(7), - NLs::CheckColumns("Table", {"key", "value"}, {"DefaultValue"}, {"key"})}); + NLs::CheckColumns("Table", {"key", "value"}, {columnName}, {"key"})}); } } From 8cb8cc3a47c3c109dce1b162fd6e3e18607eeef5 Mon Sep 17 00:00:00 2001 From: Daniil Timizhev Date: Wed, 8 Oct 2025 19:53:11 +0300 Subject: [PATCH 2/4] impl compatibility tests for default columns --- .../compatibility/test_default_columns.py | 155 ++++++++++++++++++ ydb/tests/compatibility/ya.make | 1 + ydb/tests/datashard/lib/types_of_variables.py | 32 ++++ 3 files changed, 188 insertions(+) create mode 100644 ydb/tests/compatibility/test_default_columns.py diff --git a/ydb/tests/compatibility/test_default_columns.py b/ydb/tests/compatibility/test_default_columns.py new file mode 100644 index 000000000000..fa87b7bf38d8 --- /dev/null +++ b/ydb/tests/compatibility/test_default_columns.py @@ -0,0 +1,155 @@ +# -*- coding: utf-8 -*- +import pytest +import math +from datetime import timedelta, datetime + +from ydb.tests.library.compatibility.fixtures import RestartToAnotherVersionFixture +from ydb.tests.oss.ydb_sdk_import import ydb +from ydb.tests.datashard.lib.types_of_variables import pk_types, non_pk_types, cleanup_type_name, type_to_literal_lambda + + +class TestDefaultColumns(RestartToAnotherVersionFixture): + @pytest.fixture(autouse=True, scope="function") + def setup(self): + self.table_name = "test_default_columns" + self.partitions_count = 64 + self.rows_per_partition = 10 + self.all_types = {**pk_types, **non_pk_types} + + if min(self.versions) < (24, 1): + pytest.skip("Only available since 24-1") + + yield from self.setup_cluster( + extra_feature_flags={ + "enable_add_colums_with_defaults": True, + } + ) + + # First way: create table with default columns + def test_create_table(self): + self.create_table(with_columns=True) + + self.fill_table() + self.check_table(with_columns=True) + + self.change_cluster_version() + + self.check_table(with_columns=True) + self.fill_table() + self.check_table(with_columns=True) + + # Second way: add columns with default values + def test_add_columns(self): + self.create_table(with_columns=False) + + self.fill_table() + + self.check_table(with_columns=False) + self.add_columns() + self.check_table(with_columns=True) + + self.change_cluster_version() + + self.check_table(with_columns=True) + self.drop_columns() + self.check_table(with_columns=False) + + self.fill_table() + + self.add_columns() + self.check_table(with_columns=True) + + def assert_type(self, data_type: str, values: int, values_from_rows): + result = self.all_types[data_type](values) + if data_type == "String" or data_type == "Yson": + assert values_from_rows.decode("utf-8") == result, f"{data_type}, expected {result}, received {values_from_rows.decode('utf-8')}" + elif data_type == "Float" or data_type == "DyNumber": + assert math.isclose(float(values_from_rows), float(result), rel_tol=1e-3), f"{data_type}, expected {result}, received {values_from_rows}" + elif data_type == "Interval" or data_type == "Interval64": + assert values_from_rows == timedelta(days=result), f"{data_type}, expected {timedelta(days=result)}, received {values_from_rows}" + elif data_type == "Timestamp" or data_type == "Timestamp64": + assert values_from_rows == datetime.fromtimestamp(result / 1_000_000), f"{data_type}, expected {datetime.fromtimestamp(result / 1_000_000)}, received {values_from_rows}" + elif data_type == "Json" or data_type == "JsonDocument": + assert str(values_from_rows).replace("'", "\"") == str(result), f"{data_type}, expected {result}, received {values_from_rows}" + else: + assert str(values_from_rows) == str(result), f"{data_type}, expected {result}, received {values_from_rows}" + + def create_table(self, with_columns): + with ydb.QuerySessionPool(self.driver) as session_pool: + session_pool.execute_with_retries(f""" + CREATE TABLE `{self.table_name}` ( + K1 UInt64 NOT NULL, + K2 UInt64 DEFAULT 0, + {" ".join([f"V_{cleanup_type_name(name)} {name} NOT NULL DEFAULT {type_to_literal_lambda[name](i)}," for i, name in enumerate(self.all_types.keys())]) if with_columns else ""} + PRIMARY KEY (K1, K2) + ) WITH ( + UNIFORM_PARTITIONS = {self.partitions_count} + ) + """) + + def fill_table(self): + last_partition_num = 2 ** 64 - self.rows_per_partition - 1 + queries = [] + + for partition_num in range(0, last_partition_num, last_partition_num // (self.partitions_count - 1)): + query = f""" + UPSERT INTO `{self.table_name}` (K1) + VALUES {", ".join([f"({partition_num + i})" for i in range(self.rows_per_partition)])}; + """ + queries.append(query) + + with ydb.QuerySessionPool(self.driver) as session_pool: + for query in queries: + session_pool.execute_with_retries(query) + + def check_table(self, with_columns): + last_partition_num = 2 ** 64 - self.rows_per_partition - 1 + queries = [] + + projection = ", ".join([f"V_{cleanup_type_name(name)}" for name in self.all_types.keys()]) if with_columns else "" + + for partition_num in range(0, last_partition_num, last_partition_num // (self.partitions_count - 1)): + for i in range(self.rows_per_partition): + query = f""" + SELECT {projection if projection else "*"} FROM `{self.table_name}` WHERE K1 = {partition_num + i}; + """ + queries.append(query) + + with ydb.QuerySessionPool(self.driver) as session_pool: + for query in queries: + result_sets = session_pool.execute_with_retries(query) + + rows = [] + for result_set in result_sets: + rows.extend(result_set.rows) + + assert len(rows) == 1 + for i, type_name in enumerate(self.all_types.keys()): + if with_columns: + self.assert_type(type_name, i, rows[0][f"V_{cleanup_type_name(type_name)}"]) + else: + assert f"V_{cleanup_type_name(type_name)}" not in rows[0], f"Column V_{cleanup_type_name(type_name)} should not be in the table" + + def add_columns(self): + queries = [] + for i, name in enumerate(self.all_types.keys()): + query = f""" + ALTER TABLE `{self.table_name}` + ADD COLUMN V_{cleanup_type_name(name)} {name} NOT NULL DEFAULT {type_to_literal_lambda[name](i)}; + """ + queries.append(query) + with ydb.QuerySessionPool(self.driver) as session_pool: + for query in queries: + session_pool.execute_with_retries(query) + + def drop_columns(self): + queries = [] + for name in self.all_types.keys(): + query = f""" + ALTER TABLE `{self.table_name}` + DROP COLUMN V_{cleanup_type_name(name)}; + """ + queries.append(query) + with ydb.QuerySessionPool(self.driver) as session_pool: + for query in queries: + session_pool.execute_with_retries(query) diff --git a/ydb/tests/compatibility/ya.make b/ydb/tests/compatibility/ya.make index 126e9792f730..c3e250e1c3f1 100644 --- a/ydb/tests/compatibility/ya.make +++ b/ydb/tests/compatibility/ya.make @@ -27,6 +27,7 @@ TEST_SRCS( test_node_broker_delta_protocol.py test_table_schema_compatibility.py test_workload_manager.py + test_default_columns.py udf/test_datetime2.py udf/test_digest.py udf/test_digest_regression.py diff --git a/ydb/tests/datashard/lib/types_of_variables.py b/ydb/tests/datashard/lib/types_of_variables.py index cee68006aa07..3cbf8c4ddcf2 100644 --- a/ydb/tests/datashard/lib/types_of_variables.py +++ b/ydb/tests/datashard/lib/types_of_variables.py @@ -254,3 +254,35 @@ def cleanup_type_name(type_name): "UUID", "Interval" } + +type_to_literal_lambda = { + "Int64": lambda i: i, + "Uint64": lambda i: i, + "Int32": lambda i: i, + "Uint32": lambda i: i, + "Int16": lambda i: i, + "Uint16": lambda i: i, + "Int8": lambda i: i, + "Uint8": lambda i: i, + "Bool": lambda i: bool(i), + "Decimal(15,0)": lambda i: f"Decimal('{i}', 15, 0)", + "Decimal(22,9)": lambda i: f"Decimal('{i}.123', 22, 9)", + "Decimal(35,10)": lambda i: f"Decimal('{i}.123456', 35, 10)", + "DyNumber": lambda i: f"DyNumber('{float(str(i) + 'e1')}')", + "String": lambda i: f"'String {i}'", + "Utf8": lambda i: f"'Utf8 {i}'", + "UUID": lambda i: f"Uuid('3{i:03}5678-e89b-12d3-a456-556642440000')", + "Date": lambda i: f"Date('{generate_date_value(i).strftime("%Y-%m-%d")}')", + "Datetime": lambda i: f"Datetime('{generate_datetime_value(i).strftime("%Y-%m-%dT%H:%M:%SZ")}')", + "Timestamp": lambda i: f"Timestamp('{datetime.fromtimestamp(1696200000 + i * 100).strftime("%Y-%m-%dT%H:%M:%SZ")}')", + "Interval": lambda i: f"Interval('P{i}D')", + "Date32": lambda i: f"Date32('{generate_date32_value(i).strftime("%Y-%m-%d")}')", + "Datetime64": lambda i: f"Datetime64('{generate_datetime64_value(i).strftime("%Y-%m-%dT%H:%M:%SZ")}')", + "Timestamp64": lambda i: f"Timestamp64('{datetime.fromtimestamp(1696200000 + i * 100).strftime("%Y-%m-%dT%H:%M:%SZ")}')", + "Interval64": lambda i: f"Interval64('P{i}D')", + "Float": lambda i: f"{i + 0.1}f", + "Double": lambda i: i + 0.2, + "Json": lambda i: f"Json('{{\"another_key\": {i}}}')", + "JsonDocument": lambda i: f"JsonDocument('{{\"another_doc_key\": {i}}}')", + "Yson": lambda i: f"Yson('[{i}]')", +} From 92a7811698e07847989e239913757b8bffe70b21 Mon Sep 17 00:00:00 2001 From: Daniil Timizhev Date: Wed, 8 Oct 2025 20:36:10 +0300 Subject: [PATCH 3/4] New test for writing default columns --- .../ut_column_build/ut_column_build.cpp | 91 +++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/ydb/core/tx/schemeshard/ut_column_build/ut_column_build.cpp b/ydb/core/tx/schemeshard/ut_column_build/ut_column_build.cpp index 7be3a28c5bff..a85b5c76c34c 100644 --- a/ydb/core/tx/schemeshard/ut_column_build/ut_column_build.cpp +++ b/ydb/core/tx/schemeshard/ut_column_build/ut_column_build.cpp @@ -133,6 +133,97 @@ Y_UNIT_TEST_SUITE(ColumnBuildTest) { NLs::CheckColumns("Table", {"key", "index", "value", columnName}, {}, {"key"})}); } + Y_UNIT_TEST(BuildDefaultColumnAndWrite) { + TTestBasicRuntime runtime; + TTestEnv env(runtime, TTestEnvOptions().EnableAddColumsWithDefaults(true)); + ui64 txId = 100; + ui64 tenantSchemeShard = 0; + + TestCreateServerLessDb(runtime, env, txId, tenantSchemeShard); + + TestCreateTable(runtime, tenantSchemeShard, ++txId, "/MyRoot/ServerLessDB", R"( + Name: "Table" + Columns { Name: "key" Type: "Uint32" } + Columns { Name: "index" Type: "Uint32" } + Columns { Name: "value" Type: "Utf8" } + KeyColumnNames: ["key"] + )"); + env.TestWaitNotification(runtime, txId, tenantSchemeShard); + + auto fnWriteRow = [&] (ui64 tabletId, ui32 key, ui32 index, TString value, const char* table) { + TString writeQuery = Sprintf(R"( + ( + (let key '( '('key (Uint32 '%u ) ) ) ) + (let row '( '('index (Uint32 '%u ) ) '('value (Utf8 '%s) ) ) ) + (return (AsList (UpdateRow '__user__%s key row) )) + ) + )", key, index, value.c_str(), table); + NKikimrMiniKQL::TResult result; + TString err; + NKikimrProto::EReplyStatus status = LocalMiniKQL(runtime, tabletId, writeQuery, result, err); + UNIT_ASSERT_VALUES_EQUAL(err, ""); + UNIT_ASSERT_VALUES_EQUAL(status, NKikimrProto::EReplyStatus::OK); + }; + for (ui32 delta = 0; delta < 101; ++delta) { + fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, 1 + delta, 1000 + delta, "aaaa", "Table"); + } + + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), + {NLs::PathExist, + NLs::IndexesCount(0), + NLs::PathVersionEqual(3), + NLs::CheckColumns("Table", {"key", "index", "value"}, {}, {"key"})}); + + runtime.SetLogPriority(NKikimrServices::TX_DATASHARD, NLog::PRI_TRACE); + runtime.SetLogPriority(NKikimrServices::BUILD_INDEX, NLog::PRI_TRACE); + + const TString columnName = "ColumnValue"; + Ydb::TypedValue columnDefaultValue; + columnDefaultValue.mutable_type()->set_type_id(Ydb::Type::UINT64); + columnDefaultValue.mutable_value()->set_uint64_value(1111); + + TestBuildColumn(runtime, ++txId, tenantSchemeShard, "/MyRoot/ServerLessDB", "/MyRoot/ServerLessDB/Table", columnName, columnDefaultValue, Ydb::StatusIds::SUCCESS); + + auto listing = TestListBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB"); + Y_ASSERT(listing.EntriesSize() == 1); + + env.TestWaitNotification(runtime, txId, tenantSchemeShard); + + auto descr = TestGetBuildIndex(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB", txId); + Y_ASSERT(descr.GetIndexBuild().GetState() == Ydb::Table::IndexBuildState::STATE_DONE); + + TestDescribeResult(DescribePath(runtime, tenantSchemeShard, "/MyRoot/ServerLessDB/Table"), + {NLs::PathExist, + NLs::IndexesCount(0), + NLs::PathVersionEqual(6), + NLs::CheckColumns("Table", {"key", "index", "value", columnName}, {}, {"key"})}); + + // Try to write without the default column + for (ui32 delta = 101; delta < 201; ++delta) { + fnWriteRow(TTestTxConfig::FakeHiveTablets + 6, 1 + delta, 1000 + delta, "bbbb", "Table"); + } + + auto fnWriteRowWithDefaultColumn = [&] (ui64 tabletId, ui32 key, ui32 index, TString value, ui64 columnValue, const char* table) { + TString writeQuery = Sprintf(R"( + ( + (let key '( '('key (Uint32 '%u ) ) ) ) + (let row '( '('index (Uint32 '%u ) ) '('value (Utf8 '%s) ) '('ColumnValue (Uint64 '%u ) ) ) ) + (return (AsList (UpdateRow '__user__%s key row) )) + ) + )", key, index, value.c_str(), columnValue, table); + NKikimrMiniKQL::TResult result; + TString err; + NKikimrProto::EReplyStatus status = LocalMiniKQL(runtime, tabletId, writeQuery, result, err); + UNIT_ASSERT_VALUES_EQUAL(err, ""); + UNIT_ASSERT_VALUES_EQUAL(status, NKikimrProto::EReplyStatus::OK); + }; + + // Try to write with the default column + for (ui32 delta = 201; delta < 301; ++delta) { + fnWriteRowWithDefaultColumn(TTestTxConfig::FakeHiveTablets + 6, 1 + delta, 1000 + delta, "cccc", 1234, "Table"); + } + } + Y_UNIT_TEST(BuildColumnDoesnotRestoreDeletedRows) { TTestBasicRuntime runtime(1, false); TTestEnv env(runtime, TTestEnvOptions().EnableAddColumsWithDefaults(true)); From bc3723bb22d2022eb4b1862999d39f14ffff2eaa Mon Sep 17 00:00:00 2001 From: Daniil Timizhev Date: Wed, 8 Oct 2025 20:37:00 +0300 Subject: [PATCH 4/4] Change ydbd version for tests (24.1 -> 25.3, DyNumber issue) --- ydb/tests/compatibility/test_default_columns.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ydb/tests/compatibility/test_default_columns.py b/ydb/tests/compatibility/test_default_columns.py index fa87b7bf38d8..12890c6bb59c 100644 --- a/ydb/tests/compatibility/test_default_columns.py +++ b/ydb/tests/compatibility/test_default_columns.py @@ -16,8 +16,8 @@ def setup(self): self.rows_per_partition = 10 self.all_types = {**pk_types, **non_pk_types} - if min(self.versions) < (24, 1): - pytest.skip("Only available since 24-1") + if min(self.versions) < (25, 3): + pytest.skip("Only available since 25-3") yield from self.setup_cluster( extra_feature_flags={