Skip to content

Commit dd916d3

Browse files
committed
KIKIMR-20150: fix and improve flaky test
1 parent eda727a commit dd916d3

File tree

1 file changed

+106
-8
lines changed

1 file changed

+106
-8
lines changed

ydb/core/client/client_ut.cpp

+106-8
Original file line numberDiff line numberDiff line change
@@ -2139,7 +2139,8 @@ Y_UNIT_TEST_SUITE(TClientTest) {
21392139
TPortManager tp;
21402140
ui16 port = tp.GetPort(2134);
21412141

2142-
const auto settings = TServerSettings(port);
2142+
const auto settings = TServerSettings(port)
2143+
.SetUseRealThreads(false);
21432144
TServer server(settings);
21442145
TClient client(settings);
21452146
SetupLogging(server);
@@ -2153,32 +2154,129 @@ Y_UNIT_TEST_SUITE(TClientTest) {
21532154
const TActorId edge = runtime.AllocateEdgeActor();
21542155

21552156
{
2157+
ui64 confirmationsCount = 0;
2158+
auto observeConfirmations = [&](TAutoPtr<IEventHandle>& ev) {
2159+
switch (ev->GetTypeRewrite()) {
2160+
case TEvBlobStorage::TEvPut::EventType: {
2161+
const auto* msg = ev->Get<TEvBlobStorage::TEvPut>();
2162+
// step 1 is snapshot
2163+
// step 2 is schema alter
2164+
// step 3 is expected write below
2165+
if (msg->Id.TabletID() == tabletId &&
2166+
msg->Id.Channel() == 0 &&
2167+
msg->Id.Cookie() == 1 &&
2168+
msg->Id.Step() > 2)
2169+
{
2170+
++confirmationsCount;
2171+
}
2172+
break;
2173+
}
2174+
}
2175+
return TTestActorRuntime::EEventAction::PROCESS;
2176+
};
2177+
runtime.SetObserverFunc(observeConfirmations);
2178+
21562179
const TActorId leaderTablet = runtime.Register(CreateTablet(edge, tabletInfo.Get(), setupInfo.Get(), 0, nullptr, nullptr));
21572180
const TActorId leaderId = runtime.GrabEdgeEvent<TEvTablet::TEvRestored>(edge)->Get()->UserTabletActor;
2158-
Y_UNUSED(leaderId);
2181+
2182+
// we use it to kill leader only when it has sent the write to the follower and it is confirmed
2183+
const TActorId followerTablet = runtime.Register(CreateTabletFollower(edge, tabletInfo.Get(), setupInfo.Get(), 1, nullptr, nullptr));
2184+
2185+
auto doLeaderWrite = [&](ui64 key, ui64 value) {
2186+
const char *writeQuery = R"__((
2187+
(let row_ '('('key (Uint64 '%lu))))
2188+
(let update_ '('('v_ui64 (Uint64 '%lu))))
2189+
(let result_ (UpdateRow 't_by_ui64 row_ update_))
2190+
(return (AsList result_))
2191+
))__";
2192+
2193+
THolder<TEvTablet::TEvLocalMKQL> reqWrite = MakeHolder<TEvTablet::TEvLocalMKQL>();
2194+
reqWrite->Record.MutableProgram()->MutableProgram()->SetText(Sprintf(writeQuery, key, value));
2195+
runtime.Send(new IEventHandle(leaderId, edge, reqWrite.Release()));
2196+
2197+
auto reply = runtime.GrabEdgeEvent<TEvTablet::TEvLocalMKQLResponse>(edge);
2198+
UNIT_ASSERT_VALUES_EQUAL(reply->Get()->Record.GetStatus(), 0);
2199+
};
2200+
2201+
doLeaderWrite(42, 51);
2202+
2203+
auto waitFor = [&](const auto& condition, const TString& description) {
2204+
if (!condition()) {
2205+
Cerr << "... waiting for " << description << Endl;
2206+
TDispatchOptions options;
2207+
options.CustomFinalCondition = [&]() {
2208+
return condition();
2209+
};
2210+
runtime.DispatchEvents(options);
2211+
UNIT_ASSERT_C(condition(), "... failed to wait for " << description);
2212+
}
2213+
};
2214+
2215+
waitFor([&](){ return confirmationsCount > 0; }, "Write confirmed");
21592216

21602217
runtime.Send(new IEventHandle(leaderTablet, edge, new TEvents::TEvPoisonPill()));
21612218
auto reply = runtime.GrabEdgeEvent<TEvTablet::TEvTabletDead>(edge);
21622219
UNIT_ASSERT_VALUES_EQUAL(reply->Get()->TabletID, tabletId);
2220+
2221+
runtime.Send(new IEventHandle(followerTablet, edge, new TEvents::TEvPoisonPill()));
2222+
reply = runtime.GrabEdgeEvent<TEvTablet::TEvTabletDead>(edge);
2223+
UNIT_ASSERT_VALUES_EQUAL(reply->Get()->TabletID, tabletId);
21632224
}
21642225

2165-
const TActorId followerTablet = runtime.Register(CreateTabletFollower(edge, tabletInfo.Get(), setupInfo.Get(), 1, nullptr, nullptr));
2166-
Y_UNUSED(followerTablet);
2226+
// now we start follower without its leader
21672227

2168-
const TActorId followerId = runtime.GrabEdgeEvent<TEvTablet::TEvRestored>(edge)->Get()->UserTabletActor;
2169-
Y_UNUSED(followerId);
2228+
const TActorId followerEdge = runtime.AllocateEdgeActor();
2229+
const TActorId followerTablet = runtime.Register(CreateTabletFollower(followerEdge, tabletInfo.Get(), setupInfo.Get(), 1, nullptr, nullptr));
2230+
Y_UNUSED(followerTablet);
2231+
const TActorId followerId = runtime.GrabEdgeEvent<TEvTablet::TEvRestored>(followerEdge)->Get()->UserTabletActor;
21702232

21712233
{
21722234
NTabletPipe::TClientConfig pipeClientConfig;
21732235
pipeClientConfig.AllowFollower = true;
21742236
pipeClientConfig.ForceFollower = true;
21752237
pipeClientConfig.RetryPolicy = {.RetryLimitCount = 2};
2176-
runtime.Register(NTabletPipe::CreateClient(edge, tabletId, pipeClientConfig));
2238+
runtime.Register(NTabletPipe::CreateClient(followerEdge, tabletId, pipeClientConfig));
21772239

2178-
auto reply = runtime.GrabEdgeEvent<TEvTabletPipe::TEvClientConnected>(edge);
2240+
auto reply = runtime.GrabEdgeEvent<TEvTabletPipe::TEvClientConnected>(followerEdge);
21792241

21802242
UNIT_ASSERT_VALUES_EQUAL(reply->Get()->Status, NKikimrProto::OK);
21812243
}
2244+
2245+
auto doFollowerRead = [&](ui64 key) -> TMaybe<ui64> {
2246+
const char *readQuery = R"__((
2247+
(let row_ '('('key (Uint64 '%lu))))
2248+
(let select_ '('v_ui64))
2249+
(let pgmReturn (AsList
2250+
(SetResult 'res (SelectRow 't_by_ui64 row_ select_))
2251+
))
2252+
(return pgmReturn)
2253+
))__";
2254+
2255+
THolder<TEvTablet::TEvLocalMKQL> reqRead = MakeHolder<TEvTablet::TEvLocalMKQL>();
2256+
reqRead->Record.MutableProgram()->MutableProgram()->SetText(Sprintf(readQuery, key));
2257+
runtime.Send(new IEventHandle(followerId, followerEdge, reqRead.Release()));
2258+
2259+
auto reply = runtime.GrabEdgeEvent<TEvTablet::TEvLocalMKQLResponse>(followerEdge);
2260+
UNIT_ASSERT_VALUES_EQUAL(reply->Get()->Record.GetStatus(), 0);
2261+
const auto res = reply->Get()->Record
2262+
.GetExecutionEngineEvaluatedResponse()
2263+
.GetValue()
2264+
.GetStruct(0)
2265+
.GetOptional();
2266+
if (!res.HasOptional()) {
2267+
return Nothing();
2268+
}
2269+
2270+
return res
2271+
.GetOptional()
2272+
.GetStruct(0)
2273+
.GetOptional()
2274+
.GetUint64();
2275+
};
2276+
2277+
// Perform basic sanity checks
2278+
UNIT_ASSERT_VALUES_EQUAL(doFollowerRead(41), Nothing());
2279+
UNIT_ASSERT_VALUES_EQUAL(doFollowerRead(42), 51u);
21822280
}
21832281

21842282
Y_UNIT_TEST(FollowerOfflineBoot) {

0 commit comments

Comments
 (0)