From 9be8744bb96ab00cbf25afb60ab54db5cbad95dc Mon Sep 17 00:00:00 2001 From: renadeen Date: Thu, 28 Aug 2025 16:41:01 +0300 Subject: YT-26037: Fix empty polymorphic yson struct commit_hash:918f0da0ab743372aebb95a69ed93cc6dad32df2 --- yt/yt/core/ytree/polymorphic_yson_struct-inl.h | 15 ++++++---- yt/yt/core/ytree/polymorphic_yson_struct.h | 2 +- yt/yt/core/ytree/unittests/yson_struct_ut.cpp | 39 ++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 9 deletions(-) diff --git a/yt/yt/core/ytree/polymorphic_yson_struct-inl.h b/yt/yt/core/ytree/polymorphic_yson_struct-inl.h index ed0352c2438..382742609bf 100644 --- a/yt/yt/core/ytree/polymorphic_yson_struct-inl.h +++ b/yt/yt/core/ytree/polymorphic_yson_struct-inl.h @@ -45,6 +45,16 @@ CreateInstance(TEnum value) //////////////////////////////////////////////////////////////////////////////// +template +TPolymorphicYsonStruct::TPolymorphicYsonStruct() +{ + if constexpr (DefaultType_) { + HeldType_ = *DefaultType_; + } else { + HeldType_ = {}; + } +} + template TPolymorphicYsonStruct::TPolymorphicYsonStruct(TKey key) : TPolymorphicYsonStruct(key, TMapping::CreateInstance(key)) @@ -77,11 +87,6 @@ void TPolymorphicYsonStruct::Load( SerializedStorage_ = TTraits::AsNode(source); IMapNodePtr map = SerializedStorage_->AsMap(); - if (!map || map->GetChildCount() == 0) { - // Empty struct. - return; - } - auto key = map->FindChildValue("type"); THROW_ERROR_EXCEPTION_UNLESS( key.has_value() || DefaultType_, diff --git a/yt/yt/core/ytree/polymorphic_yson_struct.h b/yt/yt/core/ytree/polymorphic_yson_struct.h index 50c4b206380..effc27ae034 100644 --- a/yt/yt/core/ytree/polymorphic_yson_struct.h +++ b/yt/yt/core/ytree/polymorphic_yson_struct.h @@ -160,7 +160,7 @@ class TPolymorphicYsonStruct public: using TImplementsYsonStructField = void; - TPolymorphicYsonStruct() = default; + TPolymorphicYsonStruct(); explicit TPolymorphicYsonStruct(TKey key); TPolymorphicYsonStruct(TKey key, TIntrusivePtr ptr) noexcept; diff --git a/yt/yt/core/ytree/unittests/yson_struct_ut.cpp b/yt/yt/core/ytree/unittests/yson_struct_ut.cpp index 31217b26b2f..792c5636c76 100644 --- a/yt/yt/core/ytree/unittests/yson_struct_ut.cpp +++ b/yt/yt/core/ytree/unittests/yson_struct_ut.cpp @@ -3478,6 +3478,18 @@ TEST(TYsonStructTest, TestPolymorphicYsonStructDefault) { TMyPolyDefault poly; + auto empty = BuildYsonNodeFluently() + .BeginMap() + .EndMap(); + + Deserialize(poly, empty->AsMap()); + EXPECT_EQ(poly.GetCurrentType(), EMyPolyDefaultType::Drv1); + + auto drv1Ptr = poly.TryGetConcrete(); + EXPECT_TRUE(drv1Ptr.operator bool()); + + /////////////// + auto node = BuildYsonNodeFluently() .BeginMap() .Item("base_field").Value(11) @@ -3487,11 +3499,13 @@ TEST(TYsonStructTest, TestPolymorphicYsonStructDefault) Deserialize(poly, node->AsMap()); EXPECT_EQ(poly.GetCurrentType(), EMyPolyDefaultType::Drv1); - auto drv1Ptr = poly.TryGetConcrete(); + drv1Ptr = poly.TryGetConcrete(); EXPECT_TRUE(drv1Ptr.operator bool()); EXPECT_EQ(drv1Ptr->BaseField, 11); EXPECT_EQ(drv1Ptr->Field1, 123); + /////////////// + node = BuildYsonNodeFluently() .BeginMap() .Item("type").Value("drv2") @@ -3502,6 +3516,8 @@ TEST(TYsonStructTest, TestPolymorphicYsonStructDefault) Deserialize(poly, node->AsMap()); EXPECT_EQ(poly.GetCurrentType(), EMyPolyDefaultType::Drv2); + /////////////// + node = BuildYsonNodeFluently() .BeginMap() .Item("base_field").Value(11) @@ -3528,6 +3544,18 @@ TEST(TYsonStructTest, TestPolymorphicYsonStructDefaultEnum) { TMyPolyDefaultEnum poly; + auto empty = BuildYsonNodeFluently() + .BeginMap() + .EndMap(); + + Deserialize(poly, empty->AsMap()); + + EXPECT_EQ(poly.GetCurrentType(), EMyPolyDefaultEnum::Base); + auto basePtr = poly.TryGetConcrete(); + EXPECT_TRUE(basePtr.operator bool()); + + /////////////// + auto node = BuildYsonNodeFluently() .BeginMap() .Item("base_field").Value(11) @@ -3537,10 +3565,12 @@ TEST(TYsonStructTest, TestPolymorphicYsonStructDefaultEnum) Deserialize(poly, node->AsMap()); EXPECT_EQ(poly.GetCurrentType(), EMyPolyDefaultEnum::Base); - auto basePtr = poly.TryGetConcrete(); + basePtr = poly.TryGetConcrete(); EXPECT_TRUE(basePtr.operator bool()); EXPECT_EQ(basePtr->BaseField, 11); + /////////////// + node = BuildYsonNodeFluently() .BeginMap() .Item("type").Value("drv1") @@ -3551,6 +3581,8 @@ TEST(TYsonStructTest, TestPolymorphicYsonStructDefaultEnum) Deserialize(poly, node->AsMap()); EXPECT_EQ(poly.GetCurrentType(), EMyPolyDefaultEnum::Drv1); + /////////////// + node = BuildYsonNodeFluently() .BeginMap() .Item("base_field").Value(11) @@ -3585,7 +3617,8 @@ TEST(TYsonStructTest, TestPolymorphicYsonStructSerializeEmpty) auto node = ConvertToNode(holder); - Deserialize(holder, node->AsMap()); + // Field `type` is mandatory for structs without configured default type. + EXPECT_THROW(Deserialize(holder, node->AsMap()), std::exception); } TEST(TYsonStructTest, TestPolymorphicYsonStructAsField) -- cgit v1.3