@@ -126,28 +126,41 @@ class MetadataChacheTTLTest : public RouterComponentTest {
126126 return get_int_field_value (json_string, " update_last_check_in_count" );
127127 }
128128
129- bool wait_for_refresh_thread_started (const ProcessWrapper &router,
130- std::chrono::milliseconds timeout) {
129+ bool wait_log_contains (const ProcessWrapper &router,
130+ const std::string &needle,
131+ std::chrono::milliseconds timeout) {
131132 if (getenv (" WITH_VALGRIND" )) {
132133 timeout *= 10 ;
133134 }
134135
135- const auto MSEC_STEP = 10ms ;
136- bool thread_started = false ;
136+ const auto MSEC_STEP = 50ms ;
137+ bool found = false ;
137138 const auto started = std::chrono::steady_clock::now ();
138139 do {
139140 const std::string log_content = router.get_full_logfile ();
140- const std::string needle = " Starting metadata cache refresh thread" ;
141- thread_started = (log_content.find (needle) != log_content.npos );
142- if (!thread_started) {
141+ found = (log_content.find (needle) != log_content.npos );
142+ if (!found) {
143143 auto step = std::min (timeout, MSEC_STEP);
144144 std::this_thread::sleep_for (std::chrono::milliseconds (step));
145145 timeout -= step;
146146 }
147- } while (!thread_started &&
148- timeout > std::chrono::steady_clock::now () - started);
147+ } while (!found && timeout > std::chrono::steady_clock::now () - started);
149148
150- return thread_started;
149+ return found;
150+ }
151+
152+ bool wait_for_refresh_thread_started (
153+ const ProcessWrapper &router, const std::chrono::milliseconds timeout) {
154+ const std::string needle = " Starting metadata cache refresh thread" ;
155+
156+ return wait_log_contains (router, needle, timeout);
157+ }
158+
159+ bool wait_metadata_read (const ProcessWrapper &router,
160+ const std::chrono::milliseconds timeout) {
161+ const std::string needle = " Potential changes detected in cluster" ;
162+
163+ return wait_log_contains (router, needle, timeout);
151164 }
152165
153166 auto &launch_router (const std::string &temp_test_dir,
@@ -481,6 +494,73 @@ INSTANTIATE_TEST_CASE_P(
481494 " unordered_ar_v2" , ClusterType::RS_V2, " 0.1" )),
482495 get_test_description);
483496
497+ class MetadataChacheTTLTestInvalidMysqlXPort
498+ : public MetadataChacheTTLTest,
499+ public ::testing::WithParamInterface<MetadataTTLTestParams> {};
500+
501+ /* *
502+ * @test Check that invalid mysqlx port in the metadata does not cause the node
503+ * to be discarded for the classic protocol connections (Bug#30617645)
504+ */
505+ TEST_P (MetadataChacheTTLTestInvalidMysqlXPort, InvalidMysqlXPort) {
506+ TempDirectory temp_test_dir;
507+ TempDirectory conf_dir (" conf" );
508+
509+ const std::string json_metadata =
510+ get_data_dir ().join (GetParam ().tracefile ).str ();
511+
512+ SCOPED_TRACE (" // single node cluster is fine for this test" );
513+ const uint16_t node_classic_port{port_pool_.get_next_available ()};
514+ const uint16_t node_http_port{port_pool_.get_next_available ()};
515+ const uint32_t kInvalidPort {76000 };
516+
517+ auto &cluster_node = launch_mysql_server_mock (
518+ json_metadata, node_classic_port, EXIT_SUCCESS, false , node_http_port);
519+ ASSERT_NO_FATAL_FAILURE (check_port_ready (cluster_node, node_classic_port));
520+
521+ ASSERT_TRUE (
522+ MockServerRestClient (node_http_port).wait_for_rest_endpoint_ready ())
523+ << cluster_node.get_full_output ();
524+
525+ SCOPED_TRACE (
526+ " // let the metadata for our single node report invalid mysqlx port" );
527+ set_mock_metadata (node_http_port, " " , {node_classic_port}, 0 , 0 , false ,
528+ " 127.0.0.1" , {kInvalidPort });
529+
530+ SCOPED_TRACE (" // launch the router with metadata-cache configuration" );
531+ const auto router_port = port_pool_.get_next_available ();
532+ const std::string metadata_cache_section = get_metadata_cache_section (
533+ {node_classic_port}, GetParam ().cluster_type , GetParam ().ttl );
534+ const std::string routing_section = get_metadata_cache_routing_section (
535+ router_port, " PRIMARY" , " first-available" );
536+ auto &router = launch_router (temp_test_dir.name (), conf_dir.name (),
537+ metadata_cache_section, routing_section,
538+ EXIT_SUCCESS, true );
539+
540+ ASSERT_NO_FATAL_FAILURE (check_port_ready (router, router_port));
541+ ASSERT_TRUE (wait_metadata_read (router, 5000ms)) << router.get_full_output ();
542+
543+ SCOPED_TRACE (
544+ " // Even though the metadata contains invalid mysqlx port we still "
545+ " should be able to connect on the classic port" );
546+ MySQLSession client;
547+ try {
548+ client.connect (" 127.0.0.1" , router_port, " username" , " password" , " " , " " );
549+ } catch (...) {
550+ FAIL () << router.get_full_logfile ();
551+ }
552+ }
553+
554+ INSTANTIATE_TEST_CASE_P (
555+ InvalidMysqlXPort, MetadataChacheTTLTestInvalidMysqlXPort,
556+ ::testing::Values (MetadataTTLTestParams(" metadata_dynamic_nodes_v2_gr.js" ,
557+ " gr_v2" , ClusterType::GR_V1, " 5" ),
558+ MetadataTTLTestParams(" metadata_dynamic_nodes.js" , " gr" ,
559+ ClusterType::GR_V2, " 5" ),
560+ MetadataTTLTestParams(" metadata_dynamic_nodes_v2_ar.js" ,
561+ " ar_v2" , ClusterType::RS_V2, " 5" )),
562+ get_test_description);
563+
484564/* *
485565 * @test Checks that the router operates smoothly when the metadata version has
486566 * changed between the metadata refreshes.
0 commit comments