iprithv commented on code in PR #4726:
URL: https://github.com/apache/solr/pull/4726#discussion_r3790344009
##########
solr/modules/gcs-repository/src/test/org/apache/solr/gcs/GCSBackupRepositoryTest.java:
##########
@@ -77,4 +93,157 @@ public void
testInitStoreDoesNotFailWithMissingCredentials() {
gcsBackupRepository.init(new NamedList<>(config));
}
+
+ @Test
+ public void testCopyIndexFileToPropagatesReadFailures() throws Exception {
+ Storage failingStorage = createFailingStorage();
+ GCSBackupRepository repo = createRepositoryWithStorage(failingStorage);
+
+ try (Directory dest = new ByteBuffersDirectory()) {
+ URI sourceDir = repo.resolve(getBaseUri(), "backup");
+ IOException thrown =
+ expectThrows(
+ IOException.class,
+ () -> repo.copyIndexFileTo(sourceDir, "any.dat", dest,
"dest.dat"));
+ assertTrue(thrown.getMessage().contains("Failed to copy index file from
GCS"));
+ assertNotNull(thrown.getCause());
+ assertTrue(thrown.getCause() instanceof StorageException);
+ assertEquals("simulated GCS read failure",
thrown.getCause().getMessage());
+ }
+ }
+
+ @Test
+ public void testCopyIndexFileToHandlesZeroByteReads() throws Exception {
+ Storage realStorage = LocalStorageHelper.customOptions(false).getService();
+ byte[] data = new byte[100];
+ random().nextBytes(data);
+ // "solrBackupsBucket" matches GCSConfigParser.DEFAULT_GCS_BUCKET_VALUE
+ String bucketName = "solrBackupsBucket";
+
+ GCSBackupRepository repo = createRepositoryWithStorage(realStorage);
+ URI sourceDir = repo.resolve(getBaseUri(), "backup");
+ BlobId blobId = BlobId.of(bucketName, sourceDir + "/source.dat");
+ realStorage.create(BlobInfo.newBuilder(blobId).build(), data);
+
+ Storage zeroReturningStorage = createZeroReturningStorage(realStorage);
+ GCSBackupRepository proxyRepo =
createRepositoryWithStorage(zeroReturningStorage);
+
+ try (Directory dest = new ByteBuffersDirectory()) {
+ proxyRepo.copyIndexFileTo(sourceDir, "source.dat", dest, "dest.dat");
+ try (IndexInput in = dest.openInput("dest.dat", IOContext.DEFAULT)) {
+ assertEquals(data.length, in.length());
+ byte[] read = new byte[data.length];
+ in.readBytes(read, 0, data.length);
+ assertArrayEquals(data, read);
+ }
+ }
+ }
+
+ @Test
+ public void testCopyIndexFileToCopiesFile() throws Exception {
+ Storage realStorage = LocalStorageHelper.customOptions(false).getService();
+ byte[] data = new byte[100];
+ random().nextBytes(data);
+ // "solrBackupsBucket" matches GCSConfigParser.DEFAULT_GCS_BUCKET_VALUE
+ String bucketName = "solrBackupsBucket";
+
+ GCSBackupRepository repo = createRepositoryWithStorage(realStorage);
+ URI sourceDir = repo.resolve(getBaseUri(), "backup");
+ BlobId blobId = BlobId.of(bucketName, sourceDir + "/source.dat");
+ realStorage.create(BlobInfo.newBuilder(blobId).build(), data);
+
+ try (Directory dest = new ByteBuffersDirectory()) {
+ repo.copyIndexFileTo(sourceDir, "source.dat", dest, "dest.dat");
+ try (IndexInput in = dest.openInput("dest.dat", IOContext.DEFAULT)) {
+ assertEquals(data.length, in.length());
+ byte[] read = new byte[data.length];
+ in.readBytes(read, 0, data.length);
+ assertArrayEquals(data, read);
+ }
+ }
+ }
+
+ private static Storage createFailingStorage() {
+ Storage delegate = LocalStorageHelper.customOptions(false).getService();
+ return (Storage)
+ Proxy.newProxyInstance(
+ Storage.class.getClassLoader(),
+ new Class<?>[] {Storage.class},
+ (proxy, method, args) -> {
+ if ("reader".equals(method.getName())) {
+ throw new StorageException(0, "simulated GCS read failure");
+ }
+ return invokeAndUnwrap(method, delegate, args);
+ });
+ }
+
+ private static Storage createZeroReturningStorage(Storage delegate) {
+ return (Storage)
+ Proxy.newProxyInstance(
+ Storage.class.getClassLoader(),
+ new Class<?>[] {Storage.class},
+ (proxy, method, args) -> {
+ if ("reader".equals(method.getName())
+ && args != null
+ && args.length == 1
+ && args[0] instanceof BlobId) {
+ ReadChannel realChannel = (ReadChannel)
invokeAndUnwrap(method, delegate, args);
+ return createZeroFirstReadChannel(realChannel);
+ }
+ return invokeAndUnwrap(method, delegate, args);
+ });
+ }
+
+ private static ReadChannel createZeroFirstReadChannel(ReadChannel delegate) {
+ return (ReadChannel)
+ Proxy.newProxyInstance(
+ ReadChannel.class.getClassLoader(),
+ new Class<?>[] {ReadChannel.class},
+ new InvocationHandler() {
+ private boolean returnedZero = false;
+
+ @Override
+ public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
+ if ("read".equals(method.getName())
+ && args != null
+ && args.length == 1
+ && args[0] instanceof ByteBuffer) {
+ if (!returnedZero) {
+ returnedZero = true;
+ return 0;
+ }
+ }
+ return invokeAndUnwrap(method, delegate, args);
+ }
+ });
+ }
+
+ private static Object invokeAndUnwrap(Method method, Object target, Object[]
args)
Review Comment:
agreed it looks a bit heavy. added a note :)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]