diff --git a/Jenkinsfile b/Jenkinsfile index acc93e005b..3d35c9e790 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -119,6 +119,7 @@ try { stopLogCatCollector(backgroundPid) storeJunitResults 'realm/realm-library/build/outputs/androidTest-results/connected/**/TEST-*.xml' storeJunitResults 'realm/kotlin-extensions/build/outputs/androidTest-results/connected/**/TEST-*.xml' + archiveRealmBackupFiles() } } @@ -233,6 +234,18 @@ def archiveServerLogs(String mongoDbRealmContainerId, String commandServerContai sh 'rm mongodb.log' } +def archiveRealmBackupFiles() { + sh 'adb pull /data/data/io.realm.test/files/realm-backup' + if (fileExists('realm-backup')) { + zip([ + 'zipFile': 'realm-backups.zip', + 'archive': true, + 'dir' : 'realm-backup' + ]) + sh 'rm -r realm-backup' + } +} + def sendMetrics(String metricName, String metricValue, Map tags) { def tagsString = getTagsString(tags) withCredentials([[$class: 'UsernamePasswordMultiBinding', credentialsId: '5b8ad2d9-61a4-43b5-b4df-b8ff6b1f16fa', passwordVariable: 'influx_pass', usernameVariable: 'influx_user']]) { diff --git a/realm/realm-library/src/androidTest/java/io/realm/RealmInMemoryTest.java b/realm/realm-library/src/androidTest/java/io/realm/RealmInMemoryTest.java index 8ca8360eae..e1371adbf2 100644 --- a/realm/realm-library/src/androidTest/java/io/realm/RealmInMemoryTest.java +++ b/realm/realm-library/src/androidTest/java/io/realm/RealmInMemoryTest.java @@ -40,7 +40,6 @@ import static junit.framework.Assert.assertTrue; import static junit.framework.Assert.fail; -@Ignore("FIXME: See https://github.com/realm/realm-java/issues/6790") @RunWith(AndroidJUnit4.class) public class RealmInMemoryTest { @@ -168,7 +167,14 @@ public void writeCopyTo() { // Tests a encrypted Realm file. testRealm.writeEncryptedCopyTo(new File(configFactory.getRoot(), encFileName), key); - onDiskRealm = Realm.getInstance(encConf); + try { + onDiskRealm = Realm.getInstance(encConf); + } catch (RealmFileException ex) { + // Attempt to backup the file in case of a crash. + // See https://github.com/realm/realm-java/issues/6790 + TestHelper.backupRealm(encConf); + throw ex; + } assertEquals(1, onDiskRealm.where(Dog.class).count()); onDiskRealm.close(); // Tests with a wrong key to see if it fails as expected. diff --git a/realm/realm-library/src/androidTest/java/io/realm/RealmTests.java b/realm/realm-library/src/androidTest/java/io/realm/RealmTests.java index 016dffcc00..fad546a606 100644 --- a/realm/realm-library/src/androidTest/java/io/realm/RealmTests.java +++ b/realm/realm-library/src/androidTest/java/io/realm/RealmTests.java @@ -4562,7 +4562,6 @@ public void hittingMaxNumberOfVersionsThrows() { } // Test for https://github.com/realm/realm-java/issues/6152 - @Ignore("FIXME: https://github.com/realm/realm-java/issues/6792") @Test @RunTestInLooperThread public void encryption_stressTest() { diff --git a/realm/realm-library/src/main/cpp/object-store b/realm/realm-library/src/main/cpp/object-store index 3f16f2287f..f18b240b8b 160000 --- a/realm/realm-library/src/main/cpp/object-store +++ b/realm/realm-library/src/main/cpp/object-store @@ -1 +1 @@ -Subproject commit 3f16f2287fdd20acc7c890c0aa77ba055ea54597 +Subproject commit f18b240b8bf592e5d5ae8045c5444f423b6d8e9d diff --git a/realm/realm-library/src/testUtils/java/io/realm/TestHelper.java b/realm/realm-library/src/testUtils/java/io/realm/TestHelper.java index 2468ef74e8..5b59cae614 100644 --- a/realm/realm-library/src/testUtils/java/io/realm/TestHelper.java +++ b/realm/realm-library/src/testUtils/java/io/realm/TestHelper.java @@ -20,6 +20,8 @@ import android.content.res.AssetManager; import android.os.Build; import android.os.Looper; +import android.util.Base64; + import androidx.test.platform.app.InstrumentationRegistry; import org.junit.Assert; @@ -27,13 +29,19 @@ import java.io.BufferedReader; import java.io.ByteArrayInputStream; import java.io.File; +import java.io.FileInputStream; +import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.OutputStream; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.nio.charset.Charset; +import java.nio.file.CopyOption; +import java.nio.file.Files; +import java.nio.file.Path; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Date; @@ -64,6 +72,7 @@ import io.realm.internal.Util; import io.realm.internal.async.RealmThreadPoolExecutor; import io.realm.log.LogLevel; +import io.realm.log.RealmLog; import io.realm.log.RealmLogger; import io.realm.rule.TestRealmConfigurationFactory; @@ -378,6 +387,76 @@ public static String getRandomString(int length) { return sb.toString(); } + // Attempts to backup a Realm file, so it can be retrieve after any tests finished + public static void backupRealm(RealmConfiguration config) { + try { + File source = new File(config.getPath()); + File backupDir = new File(BaseRealm.applicationContext.getFilesDir(), "realm-backup"); + if (!backupDir.exists() && !backupDir.mkdir()) { + throw new IllegalStateException("Could not create backup folder"); + } + File destination = new File(backupDir, config.getRealmFileName()); + int i = 0; + while (destination.exists()) { + destination = new File(backupDir, config.getRealmFileName() + "_" + i); + } + copy(source, destination); + if (config.getEncryptionKey() != null) { + RealmLog.error("Successfully backup of encrypted Realm: %s to %s. The encryption key is: \"%s\"", + source.getAbsolutePath(), destination.getAbsolutePath(), bytesToHex(config.getEncryptionKey())); + } else { + RealmLog.error("Successfully backup up: %s to %s", source.getAbsolutePath(), destination.getAbsolutePath()); + } + } catch(Exception ex) { + RealmLog.error("Attempted to backup file, but it failed.", ex); + } + } + + //Original source: https://stackoverflow.com/a/9855338/1389357 + private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); + public static String bytesToHex(byte[] bytes) { + char[] hexChars = new char[bytes.length * 2]; + for ( int j = 0; j < bytes.length; j++ ) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = hexArray[v >>> 4]; + hexChars[j * 2 + 1] = hexArray[v & 0x0F]; + } + return new String(hexChars); + } + + public static byte[] hexToBytes(String data) { + char[] hex = data.toCharArray(); + byte[] raw = new byte[hex.length / 2]; + for (int src = 0, dst = 0; dst < raw.length; ++dst) { + int hi = Character.digit(hex[src++], 16); + int lo = Character.digit(hex[src++], 16); + if ((hi < 0) || (lo < 0)) + throw new IllegalArgumentException(); + raw[dst] = (byte) (hi << 4 | lo); + } + return raw; + } + + // Credit: https://stackoverflow.com/questions/9292954/how-to-make-a-copy-of-a-file-in-android + public static void copy(File src, File dst) throws IOException { + InputStream in = new FileInputStream(src); + try { + OutputStream out = new FileOutputStream(dst); + try { + // Transfer bytes from in to out + byte[] buf = new byte[1024]; + int len; + while ((len = in.read(buf)) > 0) { + out.write(buf, 0, len); + } + } finally { + out.close(); + } + } finally { + in.close(); + } + } + /** * Returns a naive logger that can be used to test the values that are sent to the logger. */