|
11 | 11 | import org.apache.lucene.index.CorruptIndexException; |
12 | 12 | import org.apache.lucene.store.Directory; |
13 | 13 | import org.apache.lucene.store.FilterDirectory; |
14 | | -import org.opensearch.cluster.routing.RecoverySource; |
15 | 14 | import org.opensearch.cluster.routing.ShardRouting; |
16 | 15 | import org.opensearch.common.util.UploadListener; |
17 | 16 | import org.opensearch.core.action.ActionListener; |
|
21 | 20 | import org.opensearch.index.store.RemoteDirectory; |
22 | 21 | import org.opensearch.index.store.RemoteSegmentStoreDirectory; |
23 | 22 | import org.opensearch.index.store.lockmanager.RemoteStoreLockManager; |
24 | | -import org.opensearch.indices.recovery.RecoveryState; |
25 | 23 | import org.opensearch.test.OpenSearchTestCase; |
26 | 24 | import org.opensearch.threadpool.ThreadPool; |
27 | 25 |
|
@@ -102,12 +100,12 @@ public void testUploadSegmentsWithEmptyCollection() throws Exception { |
102 | 100 | exception -> fail("Should not fail for empty segments") |
103 | 101 | ); |
104 | 102 |
|
105 | | - uploaderService.uploadSegments(emptySegments, segmentSizeMap, listener, mockUploadListenerFunction); |
| 103 | + uploaderService.uploadSegments(emptySegments, segmentSizeMap, listener, mockUploadListenerFunction, false); |
106 | 104 |
|
107 | 105 | assertTrue(latch.await(1, TimeUnit.SECONDS)); |
108 | 106 | } |
109 | 107 |
|
110 | | - public void testUploadSegmentsSuccess() throws Exception { |
| 108 | + public void testUploadSegmentsSuccessWithHighPriorityUpload() throws Exception { |
111 | 109 | Collection<String> segments = Arrays.asList("segment1", "segment2"); |
112 | 110 | Map<String, Long> segmentSizeMap = new HashMap<>(); |
113 | 111 | segmentSizeMap.put("segment1", 100L); |
@@ -155,7 +153,63 @@ public void testUploadSegmentsSuccess() throws Exception { |
155 | 153 | exception -> fail("Upload should succeed: " + exception.getMessage()) |
156 | 154 | ); |
157 | 155 |
|
158 | | - testUploaderService.uploadSegments(segments, segmentSizeMap, listener, mockUploadListenerFunction); |
| 156 | + testUploaderService.uploadSegments(segments, segmentSizeMap, listener, mockUploadListenerFunction, false); |
| 157 | + |
| 158 | + assertTrue(latch.await(5, TimeUnit.SECONDS)); |
| 159 | + // Verify the upload listener was called correctly |
| 160 | + verify(mockUploadListener, times(2)).beforeUpload(any(String.class)); |
| 161 | + verify(mockUploadListener, times(2)).onSuccess(any(String.class)); |
| 162 | + } |
| 163 | + |
| 164 | + public void testUploadSegmentsSuccessWithLowPriorityUpload() throws Exception { |
| 165 | + Collection<String> segments = Arrays.asList("segment1", "segment2"); |
| 166 | + Map<String, Long> segmentSizeMap = new HashMap<>(); |
| 167 | + segmentSizeMap.put("segment1", 100L); |
| 168 | + segmentSizeMap.put("segment2", 200L); |
| 169 | + |
| 170 | + // Create a fresh mock IndexShard |
| 171 | + IndexShard freshMockShard = mock(IndexShard.class); |
| 172 | + ShardId shardId = new ShardId(new Index("test", "test"), 1); |
| 173 | + when(freshMockShard.shardId()).thenReturn(shardId); |
| 174 | + when(freshMockShard.state()).thenReturn(IndexShardState.STARTED); |
| 175 | + |
| 176 | + // Create a mock directory structure that matches what the code expects |
| 177 | + Directory innerMockDelegate = mock(Directory.class); |
| 178 | + FilterDirectory innerFilterDirectory = new TestFilterDirectory(new TestFilterDirectory(innerMockDelegate)); |
| 179 | + |
| 180 | + FilterDirectory outerFilterDirectory = new TestFilterDirectory(new TestFilterDirectory(innerFilterDirectory)); |
| 181 | + |
| 182 | + // Setup the real RemoteSegmentStoreDirectory to handle copyFrom calls |
| 183 | + RemoteDirectory remoteDirectory = mock(RemoteDirectory.class); |
| 184 | + RemoteSegmentStoreDirectory remoteSegmentStoreDirectory = new RemoteSegmentStoreDirectory( |
| 185 | + remoteDirectory, |
| 186 | + mock(RemoteDirectory.class), |
| 187 | + mock(RemoteStoreLockManager.class), |
| 188 | + freshMockShard.getThreadPool(), |
| 189 | + freshMockShard.shardId() |
| 190 | + ); |
| 191 | + |
| 192 | + // Create a new uploader service with the fresh mocks |
| 193 | + RemoteStoreUploaderService testUploaderService = new RemoteStoreUploaderService( |
| 194 | + freshMockShard, |
| 195 | + outerFilterDirectory, |
| 196 | + remoteSegmentStoreDirectory |
| 197 | + ); |
| 198 | + |
| 199 | + doAnswer(invocation -> { |
| 200 | + ActionListener<Void> callback = invocation.getArgument(5); |
| 201 | + callback.onResponse(null); |
| 202 | + return true; |
| 203 | + }).when(remoteDirectory).copyFrom(any(), any(), any(), any(), any(), any(), any(Boolean.class)); |
| 204 | + |
| 205 | + CountDownLatch latch = new CountDownLatch(1); |
| 206 | + |
| 207 | + ActionListener<Void> listener = ActionListener.wrap( |
| 208 | + response -> latch.countDown(), |
| 209 | + exception -> fail("Upload should succeed: " + exception.getMessage()) |
| 210 | + ); |
| 211 | + |
| 212 | + testUploaderService.uploadSegments(segments, segmentSizeMap, listener, mockUploadListenerFunction, true); |
159 | 213 |
|
160 | 214 | assertTrue(latch.await(5, TimeUnit.SECONDS)); |
161 | 215 | // Verify the upload listener was called correctly |
@@ -213,7 +267,7 @@ public void testUploadSegmentsWithCompositeDirectory() throws Exception { |
213 | 267 | exception -> fail("Upload should succeed: " + exception.getMessage()) |
214 | 268 | ); |
215 | 269 |
|
216 | | - testUploaderService.uploadSegments(segments, segmentSizeMap, listener, mockUploadListenerFunction); |
| 270 | + testUploaderService.uploadSegments(segments, segmentSizeMap, listener, mockUploadListenerFunction, false); |
217 | 271 |
|
218 | 272 | assertTrue(latch.await(5, TimeUnit.SECONDS)); |
219 | 273 | verify(mockCompositeDirectory).afterSyncToRemote("segment1"); |
@@ -272,7 +326,7 @@ public void testUploadSegmentsWithCorruptIndexException() throws Exception { |
272 | 326 | latch.countDown(); |
273 | 327 | }); |
274 | 328 |
|
275 | | - testUploaderService.uploadSegments(segments, segmentSizeMap, listener, mockUploadListenerFunction); |
| 329 | + testUploaderService.uploadSegments(segments, segmentSizeMap, listener, mockUploadListenerFunction, false); |
276 | 330 |
|
277 | 331 | assertTrue(latch.await(5, TimeUnit.SECONDS)); |
278 | 332 | verify(freshMockShard).failShard(eq("Index corrupted (resource=test)"), eq(corruptException)); |
@@ -331,103 +385,13 @@ public void testUploadSegmentsWithGenericException() throws Exception { |
331 | 385 | latch.countDown(); |
332 | 386 | }); |
333 | 387 |
|
334 | | - testUploaderService.uploadSegments(segments, segmentSizeMap, listener, mockUploadListenerFunction); |
| 388 | + testUploaderService.uploadSegments(segments, segmentSizeMap, listener, mockUploadListenerFunction, false); |
335 | 389 |
|
336 | 390 | assertTrue(latch.await(5, TimeUnit.SECONDS)); |
337 | 391 | verify(freshMockShard, never()).failShard(any(), any()); |
338 | 392 | verify(mockUploadListener).onFailure("segment1"); |
339 | 393 | } |
340 | 394 |
|
341 | | - public void testIsLowPriorityUpload() { |
342 | | - when(mockIndexShard.state()).thenReturn(IndexShardState.RECOVERING); |
343 | | - |
344 | | - ShardRouting mockShardRouting = mock(ShardRouting.class); |
345 | | - mockIndexShard.shardRouting = mockShardRouting; |
346 | | - when(mockShardRouting.primary()).thenReturn(true); |
347 | | - |
348 | | - RecoveryState mockRecoveryState = mock(RecoveryState.class); |
349 | | - RecoverySource mockRecoverySource = mock(RecoverySource.class); |
350 | | - when(mockRecoverySource.getType()).thenReturn(RecoverySource.Type.LOCAL_SHARDS); |
351 | | - when(mockRecoveryState.getRecoverySource()).thenReturn(mockRecoverySource); |
352 | | - when(mockIndexShard.recoveryState()).thenReturn(mockRecoveryState); |
353 | | - |
354 | | - assertTrue(uploaderService.isLowPriorityUpload()); |
355 | | - } |
356 | | - |
357 | | - public void testIsLocalOrSnapshotRecoveryOrSeedingWithLocalShards() { |
358 | | - when(mockIndexShard.state()).thenReturn(IndexShardState.RECOVERING); |
359 | | - ShardRouting mockShardRouting = mock(ShardRouting.class); |
360 | | - mockIndexShard.shardRouting = mockShardRouting; |
361 | | - when(mockShardRouting.primary()).thenReturn(true); |
362 | | - |
363 | | - RecoveryState mockRecoveryState = mock(RecoveryState.class); |
364 | | - RecoverySource mockRecoverySource = mock(RecoverySource.class); |
365 | | - when(mockRecoverySource.getType()).thenReturn(RecoverySource.Type.LOCAL_SHARDS); |
366 | | - when(mockRecoveryState.getRecoverySource()).thenReturn(mockRecoverySource); |
367 | | - when(mockIndexShard.recoveryState()).thenReturn(mockRecoveryState); |
368 | | - |
369 | | - assertTrue(uploaderService.isLocalOrSnapshotRecoveryOrSeeding()); |
370 | | - } |
371 | | - |
372 | | - public void testIsLocalOrSnapshotRecoveryOrSeedingWithSnapshot() { |
373 | | - when(mockIndexShard.state()).thenReturn(IndexShardState.RECOVERING); |
374 | | - ShardRouting mockShardRouting = mock(ShardRouting.class); |
375 | | - mockIndexShard.shardRouting = mockShardRouting; |
376 | | - when(mockShardRouting.primary()).thenReturn(true); |
377 | | - |
378 | | - RecoveryState mockRecoveryState = mock(RecoveryState.class); |
379 | | - RecoverySource mockRecoverySource = mock(RecoverySource.class); |
380 | | - when(mockRecoverySource.getType()).thenReturn(RecoverySource.Type.SNAPSHOT); |
381 | | - when(mockRecoveryState.getRecoverySource()).thenReturn(mockRecoverySource); |
382 | | - when(mockIndexShard.recoveryState()).thenReturn(mockRecoveryState); |
383 | | - |
384 | | - assertTrue(uploaderService.isLocalOrSnapshotRecoveryOrSeeding()); |
385 | | - } |
386 | | - |
387 | | - public void testIsLocalOrSnapshotRecoveryOrSeedingWithSeeding() { |
388 | | - when(mockIndexShard.state()).thenReturn(IndexShardState.RECOVERING); |
389 | | - ShardRouting mockShardRouting = mock(ShardRouting.class); |
390 | | - mockIndexShard.shardRouting = mockShardRouting; |
391 | | - when(mockShardRouting.primary()).thenReturn(true); |
392 | | - |
393 | | - RecoveryState mockRecoveryState = mock(RecoveryState.class); |
394 | | - RecoverySource mockRecoverySource = mock(RecoverySource.class); |
395 | | - when(mockRecoverySource.getType()).thenReturn(RecoverySource.Type.PEER); |
396 | | - when(mockRecoveryState.getRecoverySource()).thenReturn(mockRecoverySource); |
397 | | - when(mockIndexShard.recoveryState()).thenReturn(mockRecoveryState); |
398 | | - when(mockIndexShard.shouldSeedRemoteStore()).thenReturn(true); |
399 | | - |
400 | | - assertTrue(uploaderService.isLocalOrSnapshotRecoveryOrSeeding()); |
401 | | - } |
402 | | - |
403 | | - public void testIsLocalOrSnapshotRecoveryOrSeedingReturnsFalse() { |
404 | | - when(mockIndexShard.state()).thenReturn(IndexShardState.STARTED); |
405 | | - ShardRouting mockShardRouting = mock(ShardRouting.class); |
406 | | - mockIndexShard.shardRouting = mockShardRouting; |
407 | | - when(mockShardRouting.primary()).thenReturn(true); |
408 | | - |
409 | | - assertFalse(uploaderService.isLocalOrSnapshotRecoveryOrSeeding()); |
410 | | - } |
411 | | - |
412 | | - public void testIsLocalOrSnapshotRecoveryOrSeedingWithNonPrimary() { |
413 | | - when(mockIndexShard.state()).thenReturn(IndexShardState.RECOVERING); |
414 | | - ShardRouting mockShardRouting = mock(ShardRouting.class); |
415 | | - mockIndexShard.shardRouting = mockShardRouting; |
416 | | - when(mockShardRouting.primary()).thenReturn(true); |
417 | | - |
418 | | - assertFalse(uploaderService.isLocalOrSnapshotRecoveryOrSeeding()); |
419 | | - } |
420 | | - |
421 | | - public void testIsLocalOrSnapshotRecoveryOrSeedingWithNullRecoveryState() { |
422 | | - when(mockIndexShard.state()).thenReturn(IndexShardState.RECOVERING); |
423 | | - ShardRouting mockShardRouting = mock(ShardRouting.class); |
424 | | - mockIndexShard.shardRouting = mockShardRouting; |
425 | | - when(mockShardRouting.primary()).thenReturn(true); |
426 | | - when(mockIndexShard.recoveryState()).thenReturn(null); |
427 | | - |
428 | | - assertFalse(uploaderService.isLocalOrSnapshotRecoveryOrSeeding()); |
429 | | - } |
430 | | - |
431 | 395 | public static class TestFilterDirectory extends FilterDirectory { |
432 | 396 |
|
433 | 397 | /** |
|
0 commit comments