@@ -1659,4 +1659,80 @@ TEST_F(QuiesceDbTest, AckDuringEpochMismatch)
16591659 r.set_id = " set1" ;
16601660 r.await = sec (10 );
16611661 }));
1662- }
1662+ }
1663+
1664+ /* ==================================== */
1665+ TEST_F (QuiesceDbTest, QuiesceRootMerge)
1666+ {
1667+ ASSERT_NO_FATAL_FAILURE (configure_cluster ({ mds_gid_t (1 ) }));
1668+ managers.at (mds_gid_t (1 ))->reset_agent_callback (QUIESCING_AGENT_CB);
1669+
1670+ ASSERT_EQ (OK (), run_request ([](auto & r) {
1671+ r.set_id = " set1" ;
1672+ r.timeout = sec (60 );
1673+ r.expiration = sec (60 );
1674+ r.await = sec (60 );
1675+ r.include_roots ({ " root1" , " root2" });
1676+ }));
1677+
1678+ EXPECT_EQ (QS_QUIESCED, last_request->response .sets .at (" set1" ).rstate .state );
1679+ auto set1_exp = last_request->response .sets .at (" set1" ).expiration ;
1680+
1681+ // reset the agent callback to SILENT so that
1682+ // our sets stay RELEASING and QUIESCING forever
1683+ managers.at (mds_gid_t (1 ))->reset_agent_callback (SILENT_AGENT_CB);
1684+
1685+ ASSERT_EQ (OK (), run_request ([](auto & r) {
1686+ r.set_id = " set1" ;
1687+ r.release ();
1688+ }));
1689+
1690+ EXPECT_EQ (QS_RELEASING, last_request->response .sets .at (" set1" ).rstate .state );
1691+
1692+ ASSERT_EQ (OK (), run_request ([=](auto & r) {
1693+ r.set_id = " set2" ;
1694+ r.timeout = set1_exp*2 ;
1695+ r.expiration = set1_exp*2 ;
1696+ r.include_roots ({ " root2" , " root3" });
1697+ }));
1698+
1699+ EXPECT_EQ (QS_QUIESCING, last_request->response .sets .at (" set2" ).rstate .state );
1700+
1701+ // at this point, we should expect to have root1 RELEASING, root3 QUIESCING
1702+ // and root2, which is shared, should take the min state (QUIESCING) and the max ttl
1703+
1704+ auto agent_map = [this ]() -> std::optional<QuiesceMap> {
1705+ std::promise<QuiesceMap> agent_map_promise;
1706+ auto agent_map_future = agent_map_promise.get_future ();
1707+
1708+ managers.at (mds_gid_t (1 ))->reset_agent_callback ([&agent_map_promise](QuiesceMap& map) -> bool {
1709+ try {
1710+ agent_map_promise.set_value (map);
1711+ } catch (std::future_error) {
1712+ // ignore this if we accidentally get called more than once
1713+ }
1714+ return false ;
1715+ });
1716+
1717+ if (std::future_status::ready == agent_map_future.wait_for (std::chrono::seconds (10 ))) {
1718+ return agent_map_future.get ();
1719+ }
1720+ else {
1721+ return std::nullopt ;
1722+ }
1723+ }();
1724+
1725+ ASSERT_TRUE (agent_map.has_value ());
1726+ EXPECT_EQ (3 , agent_map->roots .size ());
1727+
1728+ {
1729+ auto const & r1 = agent_map->roots .at (" file:/root1" );
1730+ auto const & r2 = agent_map->roots .at (" file:/root2" );
1731+ auto const & r3 = agent_map->roots .at (" file:/root3" );
1732+
1733+ EXPECT_EQ (QS_RELEASING, r1.state );
1734+ EXPECT_EQ (QS_QUIESCING, r2.state );
1735+ EXPECT_EQ (QS_QUIESCING, r3.state );
1736+ EXPECT_EQ (std::max (r1.ttl , r3.ttl ), r2.ttl );
1737+ }
1738+ }
0 commit comments