aboutsummaryrefslogblamecommitdiffstats
path: root/library/cpp/lwtrace/trace_ut.cpp
blob: 9a29923e28c06e9e650a641facd5e6e8e5492571 (plain) (tree)
1
2
3
4
5
6
7
8
                
                                                  
 
                                                  
 
                                        
 








                       




                                                                                                          
                                                                                                          


                                                                                                          






                                             
                                 
                       
                        





















                                                                          


                                                             
                                  
     
 



                                                                   
                           









                                                   
                                 





























                                                                           
                           



















































































                                                         
                           










                                                       
                                                


                                                       
                                               


                                                         
                                               


                                                         
                                                


                                                       
                                               


                                                       
                                               


                                                       
                                                


                                                       
                                               


                                                       
                                               
















                                                                           
             








                                                                   
                           
































































                                                         
                           





                                                       
                                                    


                                                         
                                                    


                                                         
                                                 


                                                       
                                                


                                                       
                                                


                                                       
                                                


                                                       
                                               


                                                       
                                               













                                                                               
             









                                                                   
                           


                                                   
                                 






























                                                                             
                                                                     




































                                                                                   
                           

















                                                                    
                           















                                                   
                                                                        
     
                                  
                                                          
                    
                                                                         
                                                    
     
                        










                                                                   
                   
















                                                                                     














                                                                    
                                         








































                                                                                          
                                                                            





















































                                                                          
                                        


















                                                                                       
                     
                              
                                                             
                                

                          
                                    



                                            

                                                                    
                                         
                                           









                                                        
 
                                 
                                                                                        
                  













                                                                           
     












                                                                   
                   














































































                                                                                 
                   







































                                                                              
























































                                                                   
                         
 
#include "all.h"

#include <library/cpp/lwtrace/protos/lwtrace.pb.h>

#include <library/cpp/testing/unittest/registar.h>

#include <google/protobuf/text_format.h>

enum ESimpleEnum {
    ValueA,
    ValueB,
};

enum class EEnumClass {
    ValueC,
    ValueD,
};

#define LWTRACE_UT_PROVIDER(PROBE, EVENT, GROUPS, TYPES, NAMES)                                          \
    PROBE(NoParam, GROUPS("Group"), TYPES(), NAMES())                                                    \
    PROBE(IntParam, GROUPS("Group"), TYPES(ui32), NAMES("value"))                                        \
    PROBE(StringParam, GROUPS("Group"), TYPES(TString), NAMES("value"))                                  \
    PROBE(SymbolParam, GROUPS("Group"), TYPES(NLWTrace::TSymbol), NAMES("symbol"))                       \
    PROBE(CheckParam, GROUPS("Group"), TYPES(NLWTrace::TCheck), NAMES("value"))                          \
    PROBE(EnumParams, GROUPS("Group"), TYPES(ESimpleEnum, EEnumClass), NAMES("simpleEnum", "enumClass")) \
    PROBE(InstantParam, GROUPS("Group"), TYPES(TInstant), NAMES("value"))                                \
    PROBE(DurationParam, GROUPS("Group"), TYPES(TDuration), NAMES("value"))                              \
    PROBE(ProtoEnum, GROUPS("Group"), TYPES(NLWTrace::EOperatorType), NAMES("value"))                    \
    PROBE(IntIntParams, GROUPS("Group"), TYPES(ui32, ui64), NAMES("value1", "value2"))                   \
    /**/

LWTRACE_DECLARE_PROVIDER(LWTRACE_UT_PROVIDER)
LWTRACE_DEFINE_PROVIDER(LWTRACE_UT_PROVIDER)
LWTRACE_USING(LWTRACE_UT_PROVIDER)

using namespace NLWTrace;

Y_UNIT_TEST_SUITE(LWTraceTrace) {
#ifndef LWTRACE_DISABLE
    Y_UNIT_TEST(Smoke) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "NoParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    LogAction { }
                }
            }
        )END",
                                                             &q);
        UNIT_ASSERT(parsed);
        mngr.New("Query1", q);
        LWPROBE(NoParam);
        struct {
            void Push(TThread::TId, const TLogItem& item) {
                UNIT_ASSERT(TString(item.Probe->Event.Name) == "NoParam");
            }
        } reader;
        mngr.ReadLog("Query1", reader);

        LWPROBE(EnumParams, ValueA, EEnumClass::ValueC);
        LWPROBE(InstantParam, TInstant::Seconds(42));
        LWPROBE(DurationParam, TDuration::MilliSeconds(146));
        LWPROBE(ProtoEnum, OT_EQ);
    }

    Y_UNIT_TEST(Predicate) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "IntParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Predicate {
                    Operators {
                        Type: OT_NE
                        Argument { Param: "value" }
                        Argument { Value: "1" }
                    }
                }
                Action {
                    LogAction { }
                }
            }
        )END", &q);
        UNIT_ASSERT(parsed);
        mngr.New("QueryName", q);
        LWPROBE(IntParam, 3);
        LWPROBE(IntParam, 1);
        LWPROBE(IntParam, 4);
        LWPROBE(IntParam, 1);
        LWPROBE(IntParam, 1);
        LWPROBE(IntParam, 5);
        struct {
            ui32 expected = 3;
            ui32 logsCount = 0;
            void Push(TThread::TId, const TLogItem& item) {
                UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntParam");
                ui32 value = item.GetParam("value").GetParam().Get<ui32>();
                UNIT_ASSERT(value == expected);
                expected++;
                logsCount++;
            }
        } reader;
        mngr.ReadLog("QueryName", reader);
        UNIT_ASSERT(reader.logsCount == 3);
    }

    Y_UNIT_TEST(StatementAction) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "IntParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    StatementAction {
                        Type: ST_INC
                        Argument { Variable: "varInc" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_DEC
                        Argument { Variable: "varDec" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_MOV
                        Argument { Variable: "varMov" }
                        Argument { Value: "3" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_ADD_EQ
                        Argument { Variable: "varAddEq" }
                        Argument { Value: "2" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_ADD_EQ
                        Argument { Variable: "varAddEq" }
                        Argument { Value: "3" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_SUB_EQ
                        Argument { Variable: "varSubEq" }
                        Argument { Value: "5" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_ADD
                        Argument { Variable: "varAdd" }
                        Argument { Value: "3" }
                        Argument { Value: "2" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_SUB
                        Argument { Variable: "varSub" }
                        Argument { Value: "3" }
                        Argument { Value: "2" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_MUL
                        Argument { Variable: "varMul" }
                        Argument { Value: "6" }
                        Argument { Value: "2" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_DIV
                        Argument { Variable: "varDiv" }
                        Argument { Value: "6" }
                        Argument { Value: "2" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_MOD
                        Argument { Variable: "varMod" }
                        Argument { Value: "17" }
                        Argument { Value: "5" }
                    }
                }
            }
            Blocks {
                ProbeDesc {
                    Name: "IntParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Predicate {
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varInc" }
                        Argument { Value: "1" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varDec" }
                        Argument { Value: "-1" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varMov" }
                        Argument { Value: "3" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varAddEq" }
                        Argument { Value: "5" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varSubEq" }
                        Argument { Value: "-5" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varAdd" }
                        Argument { Value: "5" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varSub" }
                        Argument { Value: "1" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varMul" }
                        Argument { Value: "12" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varDiv" }
                        Argument { Value: "3" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varMod" }
                        Argument { Value: "2" }
                    }
                }
                Action {
                    LogAction { }
                }
            }
        )END", &q);
        UNIT_ASSERT(parsed);
        mngr.New("QueryName", q);
        LWPROBE(IntParam, 1);
        LWPROBE(IntParam, 2);
        struct {
            int logsCount = 0;
            void Push(TThread::TId, const TLogItem& item) {
                UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntParam");
                ui32 value = item.GetParam("value").GetParam().Get<ui32>();
                UNIT_ASSERT(value == 1);
                logsCount++;
            }
        } reader;
        mngr.ReadLog("QueryName", reader);
        UNIT_ASSERT(reader.logsCount == 1);
    }

    Y_UNIT_TEST(StatementActionWithParams) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "IntIntParams"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    StatementAction {
                        Type: ST_MOV
                        Argument { Variable: "varMov" }
                        Argument { Param: "value1" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_ADD_EQ
                        Argument { Variable: "varAddEq" }
                        Argument { Param: "value1" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_SUB_EQ
                        Argument { Variable: "varSubEq" }
                        Argument { Param: "value1" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_ADD
                        Argument { Variable: "varAdd" }
                        Argument { Param: "value1" }
                        Argument { Param: "value2" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_SUB
                        Argument { Variable: "varSub" }
                        Argument { Param: "value1" }
                        Argument { Param: "value2" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_MUL
                        Argument { Variable: "varMul" }
                        Argument { Param: "value1" }
                        Argument { Param: "value2" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_DIV
                        Argument { Variable: "varDiv" }
                        Argument { Param: "value1" }
                        Argument { Param: "value2" }
                    }
                }
                Action {
                    StatementAction {
                        Type: ST_MOD
                        Argument { Variable: "varMod" }
                        Argument { Param: "value1" }
                        Argument { Param: "value2" }
                    }
                }
            }
            Blocks {
                ProbeDesc {
                    Name: "IntIntParams"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Predicate {
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varMov" }
                        Argument { Param: "value1" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varAddEq" }
                        Argument { Param: "value1" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varSubEq" }
                        Argument { Value: "-22" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varAdd" }
                        Argument { Value: "25" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varSub" }
                        Argument { Value: "19" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varMul" }
                        Argument { Value: "66" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varDiv" }
                        Argument { Value: "7" }
                    }
                    Operators {
                        Type: OT_EQ
                        Argument { Variable: "varMod" }
                        Argument { Value: "1" }
                    }
                }
                Action {
                    LogAction { }
                }
            }
        )END", &q);
        UNIT_ASSERT(parsed);
        mngr.New("QueryName", q);
        LWPROBE(IntIntParams, 22, 3);
        struct {
            int logsCount = 0;
            void Push(TThread::TId, const TLogItem& item) {
                UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntIntParams");
                logsCount++;
            }
        } reader;
        mngr.ReadLog("QueryName", reader);
        UNIT_ASSERT(reader.logsCount == 1);
    }

    Y_UNIT_TEST(PerThreadLogSize) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            PerThreadLogSize: 3
            Blocks {
                ProbeDesc {
                    Name: "IntParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    LogAction { }
                }
            }
        )END", &q);
        UNIT_ASSERT(parsed);
        mngr.New("QueryRandom", q);
        LWPROBE(IntParam, 1);
        LWPROBE(IntParam, 2);
        LWPROBE(IntParam, 3);
        LWPROBE(IntParam, 4);
        struct {
            ui32 logsCount = 0;
            ui32 expected = 2;
            void Push(TThread::TId, const TLogItem& item) {
                UNIT_ASSERT(TString(item.Probe->Event.Name) == "IntParam");
                ui32 value = item.GetParam("value").GetParam().Get<ui32>();
                UNIT_ASSERT(value == expected);
                logsCount++;
                expected++;
            }
        } reader;
        mngr.ReadLog("QueryRandom", reader);
        UNIT_ASSERT(reader.logsCount == 3);
    }

    Y_UNIT_TEST(CustomAction) {
        static ui32 nCustomActionsCalls = 0;
        class TMyActionExecutor: public TCustomActionExecutor {
        public:
            TMyActionExecutor(TProbe* probe, const TCustomAction&, TSession*)
                : TCustomActionExecutor(probe, false /* not destructive */)
            {}
        private:
            bool DoExecute(TOrbit&, const TParams& params) override {
                (void)params;
                nCustomActionsCalls++;
                return true;
            }
        };

        TManager mngr(*Singleton<TProbeRegistry>(), true);
        mngr.RegisterCustomAction("MyCustomAction", [](TProbe* probe,
                                                       const TCustomAction& action,
                                                       TSession* session) {
                return new TMyActionExecutor(probe, action, session);
            }
        );
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "NoParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    CustomAction {
                        Name: "MyCustomAction"
                    }
                }
            }
        )END", &q);
        UNIT_ASSERT(parsed);
        mngr.New("Query1", q);
        LWPROBE(NoParam);
        UNIT_ASSERT(nCustomActionsCalls == 1);
    }

    Y_UNIT_TEST(SafeModeSleepException) {
        TManager mngr(*Singleton<TProbeRegistry>(), false);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "NoParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    SleepAction {
                        NanoSeconds: 1000000000
                    }
                }
            }
        )END", &q);
        UNIT_ASSERT(parsed);
        UNIT_ASSERT_EXCEPTION(mngr.New("QueryName", q), yexception);
    }

    Y_UNIT_TEST(Sleep) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "NoParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    SleepAction {
                        NanoSeconds: 1000
                    }
                }
            }
        )END", &q);
        UNIT_ASSERT(parsed);
        mngr.New("QueryName", q);
        const ui64 sleepTimeNs = 1000;  // 1 us

        TInstant t0 = Now();
        LWPROBE(NoParam);
        TInstant t1 = Now();
        UNIT_ASSERT(t1.NanoSeconds() - t0.NanoSeconds() >= sleepTimeNs);
    }

    Y_UNIT_TEST(ProtoEnumTraits) {
        using TPbEnumTraits = TParamTraits<EOperatorType>;
        TString str;
        TPbEnumTraits::ToString(TPbEnumTraits::ToStoreType(OT_EQ), &str);
        UNIT_ASSERT_STRINGS_EQUAL(str, "OT_EQ (0)");
    }

    Y_UNIT_TEST(Track) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "IntParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    RunLogShuttleAction { }
                }
            }
        )END", &q);
        UNIT_ASSERT(parsed);
        mngr.New("Query1", q);

        {
            TOrbit orbit;
            LWTRACK(IntParam, orbit, 1);
            LWTRACK(StringParam, orbit, "str");
        }

        struct {
            void Push(TThread::TId, const TTrackLog& tl) {
                UNIT_ASSERT(tl.Items.size() == 2);
                UNIT_ASSERT(TString(tl.Items[0].Probe->Event.Name) == "IntParam");
                UNIT_ASSERT(TString(tl.Items[1].Probe->Event.Name) == "StringParam");
            }
        } reader;
        mngr.ReadDepot("Query1", reader);
    }

    Y_UNIT_TEST(ShouldSerializeTracks)
    {
        TManager manager(*Singleton<TProbeRegistry>(), false);

        TOrbit orbit;
        TTraceRequest req;
        req.SetIsTraced(true);
        manager.HandleTraceRequest(req, orbit);

        LWTRACK(NoParam, orbit);
        LWTRACK(IntParam, orbit, 1);
        LWTRACK(StringParam, orbit, "str");
        LWTRACK(EnumParams, orbit, ValueA, EEnumClass::ValueC);
        LWTRACK(InstantParam, orbit, TInstant::Seconds(42));
        LWTRACK(DurationParam, orbit, TDuration::MilliSeconds(146));
        LWTRACK(ProtoEnum, orbit, OT_EQ);
        LWTRACK(IntIntParams, orbit, 1, 2);

        TTraceResponse resp;
        orbit.Serialize(0, *resp.MutableTrace());
        auto& r = resp.GetTrace();

        UNIT_ASSERT_VALUES_EQUAL(8, r.EventsSize());

        const auto& p0 = r.GetEvents(0);
        UNIT_ASSERT_VALUES_EQUAL("NoParam", p0.GetName());
        UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p0.GetProvider());
        UNIT_ASSERT_VALUES_EQUAL(0 , p0.ParamsSize());

        const auto& p1 = r.GetEvents(1);
        UNIT_ASSERT_VALUES_EQUAL("IntParam", p1.GetName());
        UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p1.GetProvider());
        UNIT_ASSERT_VALUES_EQUAL(1, p1.GetParams(0).GetUintValue());

        const auto& p2 = r.GetEvents(2);
        UNIT_ASSERT_VALUES_EQUAL("StringParam", p2.GetName());
        UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p2.GetProvider());
        UNIT_ASSERT_VALUES_EQUAL("str", p2.GetParams(0).GetStrValue());

        const auto& p3 = r.GetEvents(3);
        UNIT_ASSERT_VALUES_EQUAL("EnumParams", p3.GetName());
        UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p3.GetProvider());
        UNIT_ASSERT_VALUES_EQUAL((ui32)ValueA, p3.GetParams(0).GetIntValue());
        UNIT_ASSERT_VALUES_EQUAL((ui32)EEnumClass::ValueC, p3.GetParams(1).GetIntValue());

        const auto& p4 = r.GetEvents(4);
        UNIT_ASSERT_VALUES_EQUAL("InstantParam", p4.GetName());
        UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p4.GetProvider());
        UNIT_ASSERT_VALUES_EQUAL(42, p4.GetParams(0).GetDoubleValue());

        const auto& p5 = r.GetEvents(5);
        UNIT_ASSERT_VALUES_EQUAL("DurationParam", p5.GetName());
        UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p5.GetProvider());
        UNIT_ASSERT_VALUES_EQUAL(146, p5.GetParams(0).GetDoubleValue());

        const auto& p6 = r.GetEvents(6);
        UNIT_ASSERT_VALUES_EQUAL("ProtoEnum", p6.GetName());
        UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p6.GetProvider());
        UNIT_ASSERT_VALUES_EQUAL((int)OT_EQ, p6.GetParams(0).GetIntValue());

        const auto& p7 = r.GetEvents(7);
        UNIT_ASSERT_VALUES_EQUAL("IntIntParams", p7.GetName());
        UNIT_ASSERT_VALUES_EQUAL("LWTRACE_UT_PROVIDER", p7.GetProvider());
        UNIT_ASSERT_VALUES_EQUAL(1, p7.GetParams(0).GetUintValue());
        UNIT_ASSERT_VALUES_EQUAL(2, p7.GetParams(1).GetUintValue());
    }

    Y_UNIT_TEST(ShouldDeserializeTracks)
    {
        TManager manager(*Singleton<TProbeRegistry>(), false);

        TTraceResponse resp;
        auto& r = *resp.MutableTrace()->MutableEvents();

        auto& p0 = *r.Add();
        p0.SetName("NoParam");
        p0.SetProvider("LWTRACE_UT_PROVIDER");

        auto& p1 = *r.Add();
        p1.SetName("IntParam");
        p1.SetProvider("LWTRACE_UT_PROVIDER");
        auto& p1param = *p1.MutableParams()->Add();
        p1param.SetUintValue(1);

        auto& p2 = *r.Add();
        p2.SetName("StringParam");
        p2.SetProvider("LWTRACE_UT_PROVIDER");
        auto& p2param = *p2.MutableParams()->Add();
        p2param.SetStrValue("str");

        auto& p3 = *r.Add();
        p3.SetName("EnumParams");
        p3.SetProvider("LWTRACE_UT_PROVIDER");
        auto& p3param1 = *p3.MutableParams()->Add();
        p3param1.SetUintValue((ui64)EEnumClass::ValueC);
        auto& p3param2 = *p3.MutableParams()->Add();
        p3param2.SetIntValue((ui64)EEnumClass::ValueC);

        auto& p4 = *r.Add();
        p4.SetName("InstantParam");
        p4.SetProvider("LWTRACE_UT_PROVIDER");
        auto& p4param = *p4.MutableParams()->Add();
        p4param.SetDoubleValue(42);

        auto& p5 = *r.Add();
        p5.SetName("DurationParam");
        p5.SetProvider("LWTRACE_UT_PROVIDER");
        auto& p5param = *p5.MutableParams()->Add();
        p5param.SetDoubleValue(146);

        auto& p6 = *r.Add();
        p6.SetName("ProtoEnum");
        p6.SetProvider("LWTRACE_UT_PROVIDER");
        auto& p6param = *p6.MutableParams()->Add();
        p6param.SetIntValue((i64)OT_EQ);

        auto& p7 = *r.Add();
        p7.SetName("IntIntParams");
        p7.SetProvider("LWTRACE_UT_PROVIDER");
        auto& p7param1 = *p7.MutableParams()->Add();
        p7param1.SetIntValue(1);
        auto& p7param2 = *p7.MutableParams()->Add();
        p7param2.SetIntValue(2);

        TOrbit orbit;
        UNIT_ASSERT_VALUES_EQUAL(
            manager.HandleTraceResponse(resp, manager.GetProbesMap(), orbit).IsSuccess,
            true);
    }

    Y_UNIT_TEST(ShouldDeserializeWhatSerialized)
    {
        TManager manager(*Singleton<TProbeRegistry>(), false);

        TOrbit orbit;
        TOrbit child;

        TTraceRequest req;
        req.SetIsTraced(true);
        bool traced = manager.HandleTraceRequest(req, orbit);
        UNIT_ASSERT(traced);

        LWTRACK(NoParam, orbit);

        orbit.Fork(child);

        LWTRACK(IntParam, orbit, 1);
        LWTRACK(IntParam, child, 2);

        LWTRACK(StringParam, orbit, "str1");
        LWTRACK(StringParam, child, "str2");

        LWTRACK(EnumParams, orbit, ValueA, EEnumClass::ValueC);
        LWTRACK(InstantParam, orbit, TInstant::Seconds(42));
        LWTRACK(DurationParam, orbit, TDuration::MilliSeconds(146));
        LWTRACK(ProtoEnum, orbit, OT_EQ);
        LWTRACK(IntIntParams, orbit, 1, 2);

        orbit.Join(child);

        TTraceResponse resp1;
        auto& r1 = *resp1.MutableTrace();
        orbit.Serialize(0, r1);

        UNIT_ASSERT_VALUES_EQUAL(r1.EventsSize(), 12);

        TOrbit other;
        traced = manager.HandleTraceRequest(req, other);
        UNIT_ASSERT(traced);

        UNIT_ASSERT_VALUES_EQUAL(
            manager.HandleTraceResponse(resp1, manager.GetProbesMap(), other).IsSuccess,
            true);

        TTraceResponse resp2;
        auto& r2 = *resp2.MutableTrace();
        other.Serialize(0, r2);
        UNIT_ASSERT_VALUES_EQUAL(r2.EventsSize(), 12);

        TString proto1;
        bool parsed = NProtoBuf::TextFormat::PrintToString(resp1, &proto1);
        UNIT_ASSERT(parsed);

        TString proto2;
        parsed = NProtoBuf::TextFormat::PrintToString(resp2, &proto2);
        UNIT_ASSERT(parsed);

        UNIT_ASSERT_VALUES_EQUAL(proto1, proto2);
    }

    Y_UNIT_TEST(TrackForkJoin) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "NoParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    RunLogShuttleAction { }
                }
            }
        )END", &q);

        UNIT_ASSERT(parsed);
        mngr.New("Query1", q);

        {
            TOrbit a, b, c, d;

            // Graph:
            //         c
            //        / \
            //     b-f-b-j-b
            //    /         \
            // a-f-a-f-a-j-a-j-a
            //        \ /
            //         d
            //
            // Merged track:
            //   a-f(b)-a-f(d)-a-j(d,1)-d-a-j(b,6)-b-f(c)-b-j(c,1)-c-b-a

            LWTRACK(NoParam, a);
            a.Fork(b);
            LWTRACK(IntParam, a, 1);
            a.Fork(d);
            LWTRACK(IntParam, a, 2);

            LWTRACK(IntParam, b, 3);
            b.Fork(c);
            LWTRACK(IntParam, b, 4);

            LWTRACK(IntParam, c, 5);
            b.Join(c);
            LWTRACK(IntParam, b, 6);

            LWTRACK(IntParam, d, 7);
            a.Join(d);
            LWTRACK(IntParam, a, 8);

            a.Join(b);
            LWTRACK(IntParam, a, 9);
        }

        struct {
            void Push(TThread::TId, const TTrackLog& tl) {
                UNIT_ASSERT(tl.Items.size() == 16);
                UNIT_ASSERT(TString(tl.Items[0].Probe->Event.Name) == "NoParam");
                UNIT_ASSERT(TString(tl.Items[1].Probe->Event.Name) == "Fork");
                UNIT_ASSERT(tl.Items[2].Params.Param[0].Get<ui64>() == 1);
                UNIT_ASSERT(TString(tl.Items[3].Probe->Event.Name) == "Fork");
                UNIT_ASSERT(tl.Items[4].Params.Param[0].Get<ui64>() == 2);
                UNIT_ASSERT(TString(tl.Items[5].Probe->Event.Name) == "Join");
                UNIT_ASSERT(tl.Items[6].Params.Param[0].Get<ui64>() == 7);
                UNIT_ASSERT(tl.Items[7].Params.Param[0].Get<ui64>() == 8);
                UNIT_ASSERT(TString(tl.Items[8].Probe->Event.Name) == "Join");
                UNIT_ASSERT(tl.Items[9].Params.Param[0].Get<ui64>() == 3);
                UNIT_ASSERT(TString(tl.Items[10].Probe->Event.Name) == "Fork");
                UNIT_ASSERT(tl.Items[11].Params.Param[0].Get<ui64>() == 4);
                UNIT_ASSERT(TString(tl.Items[12].Probe->Event.Name) == "Join");
                UNIT_ASSERT(tl.Items[13].Params.Param[0].Get<ui64>() == 5);
                UNIT_ASSERT(tl.Items[14].Params.Param[0].Get<ui64>() == 6);
                UNIT_ASSERT(tl.Items[15].Params.Param[0].Get<ui64>() == 9);
            }
        } reader;
        mngr.ReadDepot("Query1", reader);
    }

    Y_UNIT_TEST(TrackForkError) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "NoParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    RunLogShuttleAction {
                        MaxTrackLength: 100
                    }
                }
            }
        )END", &q);

        UNIT_ASSERT(parsed);
        mngr.New("Query1", q);

        constexpr size_t n = (100 + 2) / 3 + 1;

        {
            TVector<TVector<TOrbit>> span;

            while (1) {
                TVector<TOrbit> orbit(n);

                LWTRACK(NoParam, orbit[0]);
                if (!orbit[0].HasShuttles()) {
                    break;
                }
                for (size_t i = 1; i < n; i++) {
                    if (!orbit[i - 1].Fork(orbit[i])) {
                        break;
                    }
                    LWTRACK(IntParam, orbit[i], i);
                }

                span.emplace_back(std::move(orbit));
            }

            for (auto& orbit: span) {
                for (auto it = orbit.rbegin(); it + 1 != orbit.rend(); it++) {
                    (it + 1)->Join(*it);
                }
            }
        }

        struct {
            void Push(TThread::TId, const TTrackLog& tl) {
                UNIT_ASSERT(tl.Items.size() == 100);
                UNIT_ASSERT(tl.Truncated);
            }
        } reader;
        mngr.ReadDepot("Query1", reader);
    }

    Y_UNIT_TEST(ShouldResetFailedForksCounterUponShuttleParking) {
        TManager mngr(*Singleton<TProbeRegistry>(), true);
        TQuery q;
        bool parsed = NProtoBuf::TextFormat::ParseFromString(R"END(
            Blocks {
                ProbeDesc {
                    Name: "NoParam"
                    Provider: "LWTRACE_UT_PROVIDER"
                }
                Action {
                    RunLogShuttleAction {
                        MaxTrackLength: 100
                        ShuttlesCount: 2
                    }
                }
            }
        )END", &q);

        UNIT_ASSERT(parsed);
        mngr.New("Query1", q);

        struct {
            ui32 cnt = 0;
            void Push(TThread::TId, const TTrackLog&) {
                ++cnt;
            }
        } reader;

        {
            // Run shuttle ans fail fork
            TOrbit initial;
            TOrbit fork1;
            TOrbit fork2;

            LWTRACK(NoParam, initial);
            UNIT_ASSERT_VALUES_EQUAL(initial.HasShuttles(), true);
            UNIT_ASSERT_VALUES_EQUAL(initial.Fork(fork1), true);
            LWTRACK(IntParam, fork1, 1);
            UNIT_ASSERT_VALUES_EQUAL(fork1.Fork(fork2), false);
            initial.Join(fork1);
        }

        mngr.ReadDepot("Query1", reader);
        UNIT_ASSERT_VALUES_EQUAL(reader.cnt, 0);

        reader.cnt = 0;

        {
            TOrbit initial;

            LWTRACK(NoParam, initial);
            UNIT_ASSERT_VALUES_EQUAL(initial.HasShuttles(), true);
        }

        mngr.ReadDepot("Query1", reader);
        UNIT_ASSERT_VALUES_EQUAL(reader.cnt, 1);
    }
#endif // LWTRACE_DISABLE
}