From 9dab0bea711cf301d847f3a85b26a708f2ace0ca Mon Sep 17 00:00:00 2001 From: Fiodar Miron <61616792+fedor-miron@users.noreply.github.com> Date: Wed, 29 May 2024 12:16:03 +0300 Subject: [PATCH] YQL-17816: fix exception in GetFolder (#4956) --- .../native/ut/yql_yt_native_folders_ut.cpp | 131 +++++++++++++----- .../gateway/native/yql_yt_native_folders.cpp | 2 +- 2 files changed, 97 insertions(+), 36 deletions(-) diff --git a/ydb/library/yql/providers/yt/gateway/native/ut/yql_yt_native_folders_ut.cpp b/ydb/library/yql/providers/yt/gateway/native/ut/yql_yt_native_folders_ut.cpp index c6be96a73ea0..a7e37a248d42 100644 --- a/ydb/library/yql/providers/yt/gateway/native/ut/yql_yt_native_folders_ut.cpp +++ b/ydb/library/yql/providers/yt/gateway/native/ut/yql_yt_native_folders_ut.cpp @@ -84,6 +84,17 @@ constexpr auto CYPRES_ACCESS_ERROR = R"( ] )"; +constexpr auto CYPRESS_BLACKBOX_ERROR = R"( +[ + { + "error" = { + "code" = 111; + "message" = "Blackbox rejected token"; + } + } +] +)"; + TVector EXPECTED_ITEMS { {"test/a/a", "table", R"({"user_attributes"={}})"}, {"test/a/b", "table", R"({"user_attributes"={}})"}, @@ -131,10 +142,12 @@ class TYtReplier : public TRequestReplier { return true; } - explicit TYtReplier(THandler handleListCommand, THandler handleGetCommand): - HandleListCommand_(handleListCommand), HandleGetCommand_(handleGetCommand) {} - explicit TYtReplier(THandler handleListCommand, THandler handleGetCommand, std::function assertion): - Assertion_(assertion), HandleListCommand_(handleListCommand), HandleGetCommand_(handleGetCommand) {} + explicit TYtReplier(THandler handleListCommand, THandler handleGetCommand, TMaybe> assertion): + HandleListCommand_(handleListCommand), HandleGetCommand_(handleGetCommand) { + if (assertion) { + Assertion_ = assertion.GetRef(); + } + } private: THttpResponse HandleExecuteBatch(THttpInput& input) { @@ -186,6 +199,24 @@ std::pair, IYtGateway::TPtr> InitTest(const NTesting::TP return {ytState, ytGateway}; } +IYtGateway::TFolderResult GetFolderResult(TYtReplier::THandler handleList, TYtReplier::THandler handleGet, +TMaybe> gatewayRequestAssertion, std::function makeFolderOptions) { + const auto port = NTesting::GetFreePort(); + NMock::TMockServer mockServer{port, + [gatewayRequestAssertion, handleList, handleGet] () {return new TYtReplier(handleList, handleGet, gatewayRequestAssertion);} + }; + + auto [ytState, ytGateway] = InitTest(port); + + IYtGateway::TFolderOptions folderOptions = makeFolderOptions(ytState->SessionId); + auto folderFuture = ytGateway->GetFolder(std::move(folderOptions)); + + folderFuture.Wait(); + ytState->Gateway->CloseSession({ytState->SessionId}); + auto folderRes = folderFuture.GetValue(); + return folderRes; +} + Y_UNIT_TEST(GetFolder) { THashMap> requiredAttributes { {"//test/a", {"type", "broken", "target_path", "user_attributes"}}, @@ -231,30 +262,25 @@ Y_UNIT_TEST(GetFolder) { } return THttpResponse{HTTP_NOT_FOUND}; }; - - const auto port = NTesting::GetFreePort(); - NMock::TMockServer mockServer{port, - [checkRequiredAttributes, handleList, handleGet] () {return new TYtReplier(handleList, handleGet, checkRequiredAttributes);} + + const auto makeFolderOptions = [] (const TString& sessionId) { + IYtGateway::TFolderOptions folderOptions{sessionId}; + TYtSettings ytSettings {}; + folderOptions.Cluster("ut_cluster") + .Config(std::make_shared(ytSettings)) + .Prefix("//test/a") + .Attributes({"user_attributes"}); + return folderOptions; }; - auto [ytState, ytGateway] = InitTest(port); - IYtGateway::TFolderOptions folderOptions{ytState->SessionId}; - TYtSettings ytSettings {}; - folderOptions.Cluster("ut_cluster") - .Config(std::make_shared(ytSettings)) - .Prefix("//test/a") - .Attributes({"user_attributes"}); - auto folderFuture = ytGateway->GetFolder(std::move(folderOptions)); - - folderFuture.Wait(); - ytState->Gateway->CloseSession({ytState->SessionId}); - auto folderRes = folderFuture.GetValue(); + auto folderRes + = GetFolderResult(handleList, handleGet, checkRequiredAttributes, makeFolderOptions); UNIT_ASSERT_EQUAL_C(folderRes.Success(), true, folderRes.Issues().ToString()); UNIT_ASSERT_EQUAL( folderRes.ItemsOrFileLink, (std::variant, TFileLinkPtr>(EXPECTED_ITEMS))); -} + } Y_UNIT_TEST(EmptyResolveIsNotError) { const auto port = NTesting::GetFreePort(); @@ -277,25 +303,60 @@ Y_UNIT_TEST(EmptyResolveIsNotError) { return resp; }; - NMock::TMockServer mockServer{port, - [handleList, handleGet] () {return new TYtReplier(handleList, handleGet);} + const auto makeFolderOptions = [] (const TString& sessionId) { + IYtGateway::TFolderOptions folderOptions{sessionId}; + TYtSettings ytSettings {}; + folderOptions.Cluster("ut_cluster") + .Config(std::make_shared(ytSettings)) + .Prefix("//test/a") + .Attributes({"user_attributes"}); + return folderOptions; }; - auto [ytState, ytGateway] = InitTest(port); - IYtGateway::TResolveOptions options{ytState->SessionId}; + auto folderRes + = GetFolderResult(handleList, handleGet, Nothing(), makeFolderOptions); + + UNIT_ASSERT_EQUAL_C(folderRes.Success(), true, folderRes.Issues().ToString()); +} - IYtGateway::TFolderOptions folderOptions{ytState->SessionId}; - TYtSettings ytSettings {}; - folderOptions.Cluster("ut_cluster") - .Config(std::make_shared(ytSettings)) - .Prefix("//test"); - auto folderFuture = ytGateway->GetFolder(std::move(folderOptions)); +Y_UNIT_TEST(GetFolderException) { + const auto port = NTesting::GetFreePort(); - folderFuture.Wait(); - ytState->Gateway->CloseSession({ytState->SessionId}); - auto folderRes = folderFuture.GetValue(); + const auto handleList = [] (TStringBuf path, const NYT::TNode& attributes) { + Y_UNUSED(path); + Y_UNUSED(attributes); + + THttpResponse resp{HTTP_UNAUTHORIZED}; + auto header = R"({"code":900,"message":"Authentication failed"})"; + resp.AddHeader(THttpInputHeader("X-YT-Error", header)); + resp.SetContent(CYPRESS_BLACKBOX_ERROR); + return resp; + }; + + const auto handleGet = [] (TStringBuf path, const NYT::TNode& attributes) { + Y_UNUSED(path); + Y_UNUSED(attributes); + + THttpResponse resp{HTTP_OK}; + resp.SetContent(""); + return resp; + }; + + const auto makeFolderOptions = [] (const TString& sessionId) { + IYtGateway::TFolderOptions folderOptions{sessionId}; + TYtSettings ytSettings {}; + folderOptions.Cluster("ut_cluster") + .Config(std::make_shared(ytSettings)) + .Prefix("//test/a") + .Attributes({"user_attributes"}); + return folderOptions; + }; + + const auto folderRes + = GetFolderResult(handleList, handleGet, Nothing(), makeFolderOptions); - UNIT_ASSERT_EQUAL_C(folderRes.Success(), true, folderRes.Issues().ToString()); + UNIT_ASSERT(!folderRes.Issues().Empty()); + UNIT_ASSERT_STRING_CONTAINS(folderRes.Issues().ToString(), "Authentication failed"); } } diff --git a/ydb/library/yql/providers/yt/gateway/native/yql_yt_native_folders.cpp b/ydb/library/yql/providers/yt/gateway/native/yql_yt_native_folders.cpp index 40f8663b975f..b5d18ebae52d 100644 --- a/ydb/library/yql/providers/yt/gateway/native/yql_yt_native_folders.cpp +++ b/ydb/library/yql/providers/yt/gateway/native/yql_yt_native_folders.cpp @@ -233,9 +233,9 @@ IYtGateway::TBatchFolderResult ExecGetFolder(const TExecContextExecuteBatch(batchOptions); try { + batchList->ExecuteBatch(batchOptions); WaitExceptionOrAll(batchRes).Wait(); for (auto& res : batchRes) { const auto items = res.ExtractValue();