66#include < ydb/core/kqp/proxy_service/kqp_script_executions.h>
77#include < ydb/core/kqp/ut/common/kqp_ut_common.h>
88#include < ydb/core/kqp/ut/federated_query/common/common.h>
9-
10- #include < ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/draft/ydb_scripting.h>
11-
129#include < ydb/library/testlib/pq_helpers/mock_pq_gateway.h>
1310#include < ydb/library/testlib/s3_recipe_helper/s3_recipe_helper.h>
11+ #include < ydb/library/yql/providers/generic/connector/libcpp/error.h>
12+ #include < ydb/library/yql/providers/generic/connector/libcpp/ut_helpers/connector_client_mock.h>
1413#include < ydb/library/yql/providers/s3/actors/yql_s3_actors_factory_impl.h>
14+ #include < ydb/public/sdk/cpp/include/ydb-cpp-sdk/client/draft/ydb_scripting.h>
1515
1616#include < fmt/format.h>
1717
@@ -22,6 +22,8 @@ using namespace NYdb::NQuery;
2222using namespace NKikimr ::NKqp::NFederatedQueryTest;
2323using namespace fmt ::literals;
2424using namespace NTestUtils ;
25+ using namespace NYql ::NConnector::NTest;
26+ using namespace NYql ::NConnector::NApi;
2527
2628namespace {
2729
@@ -65,6 +67,16 @@ class TStreamingTestFixture : public NUnitTest::TBaseFixture {
6567 return mockPqGateway;
6668 }
6769
70+ std::shared_ptr<TConnectorClientMock> SetupMockConnectorClient () {
71+ UNIT_ASSERT_C (!ConnectorClient, " ConnectorClient is already initialized" );
72+ EnsureNotInitialized (" ConnectorClient" );
73+
74+ auto mockConnectorClient = std::make_shared<TConnectorClientMock>();
75+ ConnectorClient = mockConnectorClient;
76+
77+ return mockConnectorClient;
78+ }
79+
6880 // Local kikimr test cluster
6981
7082 std::shared_ptr<TKikimrRunner> GetKikimrRunner () {
@@ -79,7 +91,7 @@ class TStreamingTestFixture : public NUnitTest::TBaseFixture {
7991 queryServiceConfig.SetEnableMatchRecognize (true );
8092 queryServiceConfig.SetProgressStatsPeriodMs (1000 );
8193
82- Kikimr = MakeKikimrRunner (true , nullptr , nullptr , AppConfig, NYql::NDq::CreateS3ActorsFactory (), {
94+ Kikimr = MakeKikimrRunner (true , ConnectorClient , nullptr , AppConfig, NYql::NDq::CreateS3ActorsFactory (), {
8395 .PqGateway = PqGateway,
8496 .CheckpointPeriod = CheckpointPeriod,
8597 });
@@ -608,6 +620,7 @@ class TStreamingTestFixture : public NUnitTest::TBaseFixture {
608620private:
609621 std::optional<NKikimrConfig::TAppConfig> AppConfig;
610622 TIntrusivePtr<NYql::IPqGateway> PqGateway;
623+ NYql::NConnector::IClient::TPtr ConnectorClient;
611624 std::shared_ptr<TKikimrRunner> Kikimr;
612625
613626 std::shared_ptr<TDriver> InternalDriver;
@@ -1565,6 +1578,172 @@ Y_UNIT_TEST_SUITE(KqpStreamingQueriesDdl) {
15651578 WaitMockPqReadSession (pqGateway, inputTopicName)->AddDataReceivedEvent (sampleMessages);
15661579 ReadMockPqMessages (WaitMockPqWriteSession (pqGateway, outputTopicName), sampleResult);
15671580 }
1581+
1582+ Y_UNIT_TEST_F (StreamingQueryWithYdbJoin, TStreamingTestFixture) {
1583+ // Test that defaults are overridden for streaming queries
1584+ auto & setting = *SetupAppConfig ().MutableKQPConfig ()->AddSettings ();
1585+ setting.SetName (" HashJoinMode" );
1586+ setting.SetValue (" grace" );
1587+
1588+ const auto connectorClient = SetupMockConnectorClient ();
1589+ const auto pqGateway = SetupMockPqGateway ();
1590+
1591+ constexpr char inputTopicName[] = " inputTopicName" ;
1592+ constexpr char outputTopicName[] = " outputTopicName" ;
1593+ CreateTopic (inputTopicName);
1594+ CreateTopic (outputTopicName);
1595+
1596+ constexpr char pqSourceName[] = " pqSourceName" ;
1597+ CreatePqSource (pqSourceName);
1598+
1599+ constexpr char ydbSourceName[] = " ydbSourceName" ;
1600+ ExecQuery (fmt::format (R"(
1601+ CREATE OBJECT secret_name (TYPE SECRET) WITH (value = "{token}");
1602+ CREATE EXTERNAL DATA SOURCE `{ydb_source}` WITH (
1603+ SOURCE_TYPE = "Ydb",
1604+ LOCATION = "{ydb_location}",
1605+ DATABASE_NAME = "{ydb_database_name}",
1606+ AUTH_METHOD = "TOKEN",
1607+ TOKEN_SECRET_NAME = "secret_name",
1608+ USE_TLS = "FALSE"
1609+ );)" ,
1610+ " ydb_source" _a = ydbSourceName,
1611+ " ydb_location" _a = YDB_ENDPOINT,
1612+ " ydb_database_name" _a = YDB_DATABASE,
1613+ " token" _a = BUILTIN_ACL_ROOT
1614+ ));
1615+
1616+ constexpr char ydbTable[] = " lookup" ;
1617+ ExecExternalQuery (fmt::format (R"(
1618+ CREATE TABLE `{table}` (
1619+ fqdn String,
1620+ payload String,
1621+ PRIMARY KEY (fqdn)
1622+ ))" ,
1623+ " table" _a = ydbTable
1624+ ));
1625+
1626+ { // Prepare connector mock
1627+ NYql::TGenericDataSourceInstance dataSourceInstance;
1628+ dataSourceInstance.set_kind (NYql::YDB);
1629+ dataSourceInstance.set_database (YDB_DATABASE);
1630+ dataSourceInstance.set_use_tls (false );
1631+ dataSourceInstance.set_protocol (NYql::NATIVE);
1632+
1633+ auto & endpoint = *dataSourceInstance.mutable_endpoint ();
1634+ TIpPort port;
1635+ NHttp::CrackAddress (YDB_ENDPOINT, *endpoint.mutable_host (), port);
1636+ endpoint.set_port (port);
1637+
1638+ auto & iamToken = *dataSourceInstance.mutable_credentials ()->mutable_token ();
1639+ iamToken.set_type (" IAM" );
1640+ iamToken.set_value (BUILTIN_ACL_ROOT);
1641+
1642+ TTypeMappingSettings typeMappingSettings;
1643+ typeMappingSettings.set_date_time_format (STRING_FORMAT);
1644+
1645+ auto describeTableBuilder = connectorClient->ExpectDescribeTable ();
1646+ describeTableBuilder
1647+ .Table (ydbTable)
1648+ .DataSourceInstance (dataSourceInstance)
1649+ .TypeMappingSettings (typeMappingSettings);
1650+
1651+ auto listSplitsBuilder = connectorClient->ExpectListSplits ();
1652+ listSplitsBuilder.Select ()
1653+ .DataSourceInstance (dataSourceInstance)
1654+ .Table (ydbTable);
1655+
1656+ const std::vector<std::string> fqdnColumn = {" host1.example.com" , " host2.example.com" , " host3.example.com" };
1657+ const std::vector<std::string> payloadColumn = {" P1" , " P2" , " P3" };
1658+ auto readSplitsBuilder = connectorClient->ExpectReadSplits ();
1659+ readSplitsBuilder
1660+ .Filtering (TReadSplitsRequest::FILTERING_OPTIONAL)
1661+ .Split ()
1662+ .Description (" some binary description" )
1663+ .Select ()
1664+ .Table (ydbTable)
1665+ .DataSourceInstance (dataSourceInstance)
1666+ .What ()
1667+ .Column (" fqdn" , Ydb::Type::STRING)
1668+ .Column (" payload" , Ydb::Type::STRING);
1669+
1670+ const auto builtResults = [&]() {
1671+ describeTableBuilder.Response ()
1672+ .Column (" fqdn" , Ydb::Type::STRING)
1673+ .Column (" payload" , Ydb::Type::STRING);
1674+
1675+ listSplitsBuilder.Result ()
1676+ .AddResponse (NYql::NConnector::NewSuccess ())
1677+ .Description (" some binary description" )
1678+ .Select ()
1679+ .DataSourceInstance (dataSourceInstance)
1680+ .What ()
1681+ .Column (" fqdn" , Ydb::Type::STRING)
1682+ .Column (" payload" , Ydb::Type::STRING);
1683+
1684+ readSplitsBuilder.Result ()
1685+ .AddResponse (
1686+ MakeRecordBatch (
1687+ MakeArray<arrow::BinaryBuilder>(" fqdn" , fqdnColumn, arrow::binary ()),
1688+ MakeArray<arrow::BinaryBuilder>(" payload" , payloadColumn, arrow::binary ())
1689+ ),
1690+ NYql::NConnector::NewSuccess ()
1691+ );
1692+ };
1693+
1694+ builtResults ();
1695+ builtResults (); // Streaming queries compiled twice, also in test results requested twice due to retry
1696+ }
1697+
1698+ constexpr char queryName[] = " streamingQuery" ;
1699+ ExecQuery (fmt::format (R"(
1700+ CREATE STREAMING QUERY `{query_name}` AS
1701+ DO BEGIN
1702+ $ydb_lookup = SELECT * FROM `{ydb_source}`.`{ydb_table}`;
1703+
1704+ $pq_source = SELECT * FROM `{pq_source}`.`{input_topic}` WITH (
1705+ FORMAT = "json_each_row",
1706+ SCHEMA (
1707+ time Int32 NOT NULL,
1708+ event String,
1709+ host String
1710+ )
1711+ );
1712+
1713+ $joined = SELECT l.payload AS payload, p.* FROM $pq_source AS p
1714+ LEFT JOIN $ydb_lookup AS l
1715+ ON (l.fqdn = p.host);
1716+
1717+ INSERT INTO `{pq_source}`.`{output_topic}`
1718+ SELECT Unwrap(event || "-" || payload) FROM $joined
1719+ END DO;)" ,
1720+ " query_name" _a = queryName,
1721+ " pq_source" _a = pqSourceName,
1722+ " ydb_source" _a = ydbSourceName,
1723+ " ydb_table" _a = ydbTable,
1724+ " input_topic" _a = inputTopicName,
1725+ " output_topic" _a = outputTopicName
1726+ ));
1727+
1728+ CheckScriptExecutionsCount (1 , 1 );
1729+
1730+ auto readSession = WaitMockPqReadSession (pqGateway, inputTopicName);
1731+ const std::vector<IMockPqReadSession::TMessage> sampleMessages = {
1732+ {0 , R"( {"time": 0, "event": "A", "host": "host1.example.com"})" },
1733+ {1 , R"( {"time": 1, "event": "B", "host": "host3.example.com"})" },
1734+ {2 , R"( {"time": 2, "event": "A", "host": "host1.example.com"})" },
1735+ };
1736+ readSession->AddDataReceivedEvent (sampleMessages);
1737+
1738+ auto writeSession = WaitMockPqWriteSession (pqGateway, outputTopicName);
1739+ const std::vector<TString> sampleResult = {" A-P1" , " B-P3" , " A-P1" };
1740+ ReadMockPqMessages (writeSession, sampleResult);
1741+
1742+ readSession->AddCloseSessionEvent (EStatus::UNAVAILABLE, {NIssue::TIssue (" Test pq session failure" )});
1743+
1744+ WaitMockPqReadSession (pqGateway, inputTopicName)->AddDataReceivedEvent (sampleMessages);
1745+ ReadMockPqMessages (WaitMockPqWriteSession (pqGateway, outputTopicName), sampleResult);
1746+ }
15681747}
15691748
15701749} // namespace NKikimr::NKqp
0 commit comments