1919
2020import static io .micronaut .http .HttpStatus .BAD_REQUEST ;
2121import static io .micronaut .http .HttpStatus .OK ;
22+ import static java .util .concurrent .TimeUnit .SECONDS ;
2223import static java .util .stream .Collectors .toSet ;
2324import static org .apache .ignite .internal .TestDefaultProfilesNames .DEFAULT_AIPERSIST_PROFILE_NAME ;
2425import static org .apache .ignite .internal .rest .matcher .MicronautHttpResponseMatcher .assertThrowsProblem ;
2526import static org .apache .ignite .internal .rest .matcher .MicronautHttpResponseMatcher .hasStatus ;
2627import static org .apache .ignite .internal .rest .matcher .ProblemMatcher .isProblem ;
28+ import static org .apache .ignite .internal .testframework .matchers .CompletableFutureMatcher .willCompleteSuccessfully ;
2729import static org .hamcrest .MatcherAssert .assertThat ;
2830import static org .hamcrest .Matchers .allOf ;
2931
3638import java .util .Collection ;
3739import java .util .List ;
3840import java .util .Set ;
41+ import java .util .concurrent .CompletableFuture ;
3942import java .util .stream .Collectors ;
4043import org .apache .ignite .Ignite ;
4144import org .apache .ignite .internal .ClusterConfiguration ;
4245import org .apache .ignite .internal .ClusterPerClassIntegrationTest ;
46+ import org .apache .ignite .internal .app .IgniteImpl ;
47+ import org .apache .ignite .internal .placementdriver .ReplicaMeta ;
48+ import org .apache .ignite .internal .placementdriver .message .LeaseGrantedMessage ;
49+ import org .apache .ignite .internal .placementdriver .message .LeaseGrantedMessageResponse ;
50+ import org .apache .ignite .internal .placementdriver .message .PlacementDriverMessagesFactory ;
51+ import org .apache .ignite .internal .placementdriver .message .StopLeaseProlongationMessage ;
52+ import org .apache .ignite .internal .replicator .ZonePartitionId ;
4353import org .apache .ignite .internal .rest .api .recovery .RestartZonePartitionsRequest ;
54+ import org .apache .ignite .internal .table .TableImpl ;
55+ import org .apache .ignite .internal .wrapper .Wrappers ;
4456import org .hamcrest .Matcher ;
4557import org .hamcrest .Matchers ;
4658import org .junit .jupiter .api .BeforeAll ;
59+ import org .junit .jupiter .api .BeforeEach ;
4760import org .junit .jupiter .api .Disabled ;
4861import org .junit .jupiter .api .Test ;
4962
5063/** Test for disaster recovery restart partitions command. */
5164@ MicronautTest
5265public class ItDisasterRecoveryControllerRestartPartitionsTest extends ClusterPerClassIntegrationTest {
66+ private static final PlacementDriverMessagesFactory PLACEMENT_DRIVER_MESSAGES_FACTORY = new PlacementDriverMessagesFactory ();
67+
5368 private static final String NODE_URL = "http://localhost:" + ClusterConfiguration .DEFAULT_BASE_HTTP_PORT ;
5469
5570 private static final String FIRST_ZONE = "first_ZONE" ;
@@ -65,10 +80,17 @@ public class ItDisasterRecoveryControllerRestartPartitionsTest extends ClusterPe
6580 @ BeforeAll
6681 public void setUp () {
6782 sql (String .format ("CREATE ZONE \" %s\" storage profiles ['%s']" , FIRST_ZONE , DEFAULT_AIPERSIST_PROFILE_NAME ));
68- sql (String .format ("CREATE TABLE PUBLIC. \" %s \" (id INT PRIMARY KEY, val INT) ZONE \" %s\" " , TABLE_NAME ,
83+ sql (String .format ("CREATE TABLE %s (id INT PRIMARY KEY, val INT) ZONE \" %s\" " , TABLE_NAME ,
6984 FIRST_ZONE ));
7085 }
7186
87+ @ BeforeEach
88+ public void beforeEach () {
89+ for (IgniteImpl node : runningNodesList ()) {
90+ node .stopDroppingMessages ();
91+ }
92+ }
93+
7294 @ Test
7395 public void testRestartPartitionZoneNotFound () {
7496 String unknownZone = "unknown_zone" ;
@@ -135,7 +157,6 @@ public void testRestartAllPartitions() {
135157 }
136158
137159 @ Test
138- @ Disabled ("https://issues.apache.org/jira/browse/IGNITE-26377" )
139160 public void testRestartSpecifiedPartitions () {
140161 MutableHttpRequest <?> post = restartPartitionsRequest (Set .of (), FIRST_ZONE , Set .of (0 , 1 ));
141162
@@ -151,6 +172,64 @@ public void testRestartPartitionsByNodes() {
151172 assertThat (client .toBlocking ().exchange (post ), hasStatus (OK ));
152173 }
153174
175+ @ Test
176+ public void testRestartPartitionDuringLeaseNegotiation () {
177+ IgniteImpl node = anyNode ();
178+
179+ int zoneId = Wrappers .unwrap (node .tables ().table (TABLE_NAME ), TableImpl .class ).zoneId ();
180+ ZonePartitionId partId = new ZonePartitionId (zoneId , 0 );
181+
182+ CompletableFuture <ReplicaMeta > primaryReplicaFut = anyNode ().placementDriver ().awaitPrimaryReplica (
183+ partId ,
184+ node .clock ().now (),
185+ 10 ,
186+ SECONDS
187+ );
188+
189+ assertThat (primaryReplicaFut , willCompleteSuccessfully ());
190+
191+ log .info ("Test: primary replica [groupId={}, leaseholder={}]" , partId , primaryReplicaFut .join ().getLeaseholder ());
192+
193+ CompletableFuture <?> newNegotiationFuture = new CompletableFuture <>();
194+
195+ for (IgniteImpl n : runningNodesList ()) {
196+ n .dropMessages ((recp , msg ) -> {
197+ if (msg instanceof LeaseGrantedMessage ) {
198+ LeaseGrantedMessage lgm = (LeaseGrantedMessage ) msg ;
199+ if (lgm .groupId ().equals (partId )) {
200+ log .info ("Test: new negotiation begins [groupId={}, leaseholder={}]" , lgm .groupId (), recp );
201+ newNegotiationFuture .complete (null );
202+ }
203+ }
204+
205+ if (msg instanceof LeaseGrantedMessageResponse ) {
206+ log .info ("Test: lease negotiation tries to finish [accepted={}]" , ((LeaseGrantedMessageResponse ) msg ).accepted ());
207+ return true ;
208+ }
209+
210+ return false ;
211+ });
212+ }
213+
214+ StopLeaseProlongationMessage stopMsg = PLACEMENT_DRIVER_MESSAGES_FACTORY .stopLeaseProlongationMessage ()
215+ .groupId (partId )
216+ .build ();
217+
218+ for (IgniteImpl n : runningNodesList ()) {
219+ for (IgniteImpl recp : runningNodesList ()) {
220+ n .clusterService ().messagingService ().invoke (recp .clusterService ().topologyService ().localMember (), stopMsg , 3000 );
221+ }
222+ }
223+
224+ assertThat (newNegotiationFuture , willCompleteSuccessfully ());
225+
226+ log .info ("Test: partition restart" );
227+
228+ MutableHttpRequest <?> post = restartPartitionsRequest (Set .of (), FIRST_ZONE , Set .of (0 ));
229+
230+ assertThat (client .toBlocking ().exchange (post ), hasStatus (OK ));
231+ }
232+
154233 private static Set <String > nodeNames (int count ) {
155234 return CLUSTER .runningNodes ()
156235 .map (Ignite ::name )
0 commit comments