Skip to content

Commit 4d3640b

Browse files
committed
ParseCacheDirMigrationUtils::
- To perform Parse SDK Cache Dir migration operation. ParseCacheDirMigrationUtilsTest:: - Added test to check migration manually without SDK initialization - Added test to run migration routine only once on SDK initialization
1 parent a4c11c9 commit 4d3640b

File tree

2 files changed

+139
-62
lines changed

2 files changed

+139
-62
lines changed
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
package com.parse;
2+
3+
import android.content.Context;
4+
5+
import java.io.File;
6+
import java.util.ArrayList;
7+
8+
/**
9+
* The {@code ParseMigrationUtils} class perform caching dir migration operation for {@code Parse} SDK.
10+
*/
11+
public class ParseCacheDirMigrationUtils {
12+
private final String TAG = this.getClass().getName();
13+
private final Object lock = new Object();
14+
private final Context context;
15+
16+
protected ParseCacheDirMigrationUtils(Context context) {
17+
this.context = context;
18+
}
19+
20+
/*Start old data migrations to new respective locations ("/files/com.parse/", "/cache/com.parse/")*/
21+
protected void runMigrations() {
22+
synchronized (lock) {
23+
runSilentMigration(context);
24+
}
25+
}
26+
27+
private void runSilentMigration(Context context) {
28+
ArrayList<File> filesToBeMigrated = new ArrayList<>();
29+
ParseFileUtils.getAllNestedFiles(
30+
getOldParseDir(context).getAbsolutePath(),
31+
filesToBeMigrated
32+
);
33+
if (filesToBeMigrated.isEmpty()) {
34+
return;
35+
}
36+
boolean useFilesDir = false;
37+
//Hard coded config file names list.
38+
String[] configNamesList = {"installationId", "currentUser", "currentConfig", "currentInstallation", "LocalId", "pushState"};
39+
//Start migration for each files in `allFiles`.
40+
for (File itemToMove : filesToBeMigrated) {
41+
try {
42+
for (String configName : configNamesList) {
43+
if (itemToMove.getAbsolutePath().contains(configName)) {
44+
useFilesDir = true;
45+
break;
46+
} else {
47+
useFilesDir = false;
48+
}
49+
}
50+
File fileToSave = new File(
51+
(useFilesDir ? context.getFilesDir() : context.getCacheDir())
52+
+ "/com.parse/" +
53+
getFileOldDir(context, itemToMove),
54+
itemToMove.getName());
55+
//Perform copy operation if file doesn't exist in the new directory.
56+
if (!fileToSave.exists()) {
57+
ParseFileUtils.copyFile(itemToMove, fileToSave);
58+
logMigrationStatus(itemToMove.getName(), itemToMove.getPath(), fileToSave.getAbsolutePath(), "Successful.");
59+
} else {
60+
logMigrationStatus(itemToMove.getName(), itemToMove.getPath(), fileToSave.getAbsolutePath(), "Already exist in new location.");
61+
}
62+
ParseFileUtils.deleteQuietly(itemToMove);
63+
PLog.v(TAG, "File deleted: " + "{" + itemToMove.getName() + "}" + " successfully");
64+
} catch (Exception e) {
65+
e.printStackTrace();
66+
}
67+
}
68+
//Check again, if all files has been resolved or not. If yes, delete the old dir "app_Parse".
69+
filesToBeMigrated.clear();
70+
ParseFileUtils.getAllNestedFiles(getOldParseDir(context).getAbsolutePath(), filesToBeMigrated);
71+
if (filesToBeMigrated.isEmpty()) {
72+
try {
73+
ParseFileUtils.deleteDirectory(getOldParseDir(context));
74+
} catch (Exception e) {
75+
e.printStackTrace();
76+
}
77+
}
78+
PLog.v(TAG, "Migration completed.");
79+
}
80+
81+
private String getFileOldDir(Context context, File file) {
82+
//Parse the old sub directory name where the file should be moved (new location) by following the old sub directory name.
83+
String temp = file
84+
.getAbsolutePath()
85+
.replace(
86+
getOldParseDir(context).getAbsolutePath(), "")
87+
.replace("/" + file.getName(), "");
88+
//Before returning the path, replace file name from the last, eg. dir name & file name could be same, as we want to get only dir name.
89+
return replaceLast(temp, file.getName());
90+
}
91+
92+
private void logMigrationStatus(String fileName, String oldPath, String newPath, String status) {
93+
PLog.v(TAG, "Migration for file: " + "{" + fileName + "}" + " from {" + oldPath + "} to {" + newPath + "}, Status: " + status);
94+
}
95+
96+
/*Replace a given string from the last*/
97+
private String replaceLast(String text, String regex) {
98+
return text.replaceFirst("(?s)" + regex + "(?!.*?" + regex + ")", "");
99+
}
100+
101+
private File getOldParseDir(Context context) {
102+
return context.getDir("Parse", Context.MODE_PRIVATE);
103+
}
104+
105+
106+
}

parse/src/test/java/com/parse/ParseCacheDirMigrationTest.java renamed to parse/src/test/java/com/parse/ParseCacheDirMigrationUtilsTest.java

Lines changed: 33 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,62 @@
11
package com.parse;
22

33
import android.content.Context;
4+
45
import androidx.test.platform.app.InstrumentationRegistry;
6+
57
import org.junit.After;
68
import org.junit.Before;
79
import org.junit.Test;
810
import org.junit.runner.RunWith;
911
import org.robolectric.RobolectricTestRunner;
12+
1013
import java.io.File;
1114
import java.util.ArrayList;
1215

1316
@RunWith(RobolectricTestRunner.class)
14-
public class ParseCacheDirMigrationTest {
17+
public class ParseCacheDirMigrationUtilsTest {
1518
ArrayList<File> writtenFiles = new ArrayList<>();
19+
private ParseCacheDirMigrationUtils utils;
1620

1721
@Before
1822
public void setUp() throws Exception {
19-
Context context = InstrumentationRegistry.getInstrumentation().getContext();
20-
ParsePlugins.reset();
21-
Parse.Configuration configuration =
22-
new Parse.Configuration.Builder(context).applicationId("1234").build();
23-
ParsePlugins.initialize(context, configuration);
23+
utils = new ParseCacheDirMigrationUtils(InstrumentationRegistry.getInstrumentation().getContext());
2424
writtenFiles.clear();
2525
}
2626

2727
@After
2828
public void tearDown() throws Exception {
29-
ParsePlugins.reset();
3029
writtenFiles.clear();
3130
}
3231

3332
@Test
34-
public void manualMigrationBeforeAccessNewCacheAPIs() {
33+
public void testMigrationOnParseSDKInitialization() {
34+
prepareForMockFilesWriting();
35+
writtenFiles.addAll(writeSomeMockFiles(true));
36+
Parse.Configuration configuration =
37+
new Parse.Configuration.Builder(InstrumentationRegistry.getInstrumentation().getContext())
38+
.applicationId(BuildConfig.LIBRARY_PACKAGE_NAME)
39+
.server("https://api.parse.com/1")
40+
.enableLocalDataStore()
41+
.build();
42+
Parse.initialize(configuration);
43+
}
44+
45+
@Test
46+
public void testMockMigration() {
3547
prepareForMockFilesWriting();
36-
writtenFiles.addAll(writeSomeMockFiles(false));
48+
writtenFiles.addAll(writeSomeMockFiles(true));
3749

38-
//Run migration manually.
39-
ParsePlugins.get().runSilentMigration();
50+
//Run migration.
51+
utils.runMigrations();
4052

4153
//Check for cache file after migration.
42-
File cacheDir = ParsePlugins.get().getCacheDir();
54+
File cacheDir = InstrumentationRegistry.getInstrumentation().getContext().getCacheDir();
4355
ArrayList<File> migratedCaches = new ArrayList<>();
4456
ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches);
4557

4658
//Check for files file after migration.
47-
File filesDir = ParsePlugins.get().getFilesDir();
59+
File filesDir = InstrumentationRegistry.getInstrumentation().getContext().getFilesDir();
4860
ArrayList<File> migratedFiles = new ArrayList<>();
4961
ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles);
5062

@@ -57,62 +69,21 @@ public void manualMigrationBeforeAccessNewCacheAPIs() {
5769
assert sizeBeforeMigrations == sizeAfterMigration;
5870
}
5971

60-
@Test
61-
public void autoMigrationBeforeAccessFilesDir() {
62-
prepareForMockFilesWriting();
63-
writtenFiles.addAll(writeSomeMockFiles(false));
64-
ArrayList<File> migratedFiles = new ArrayList<>();
65-
//Auto migration
66-
File filesDir = ParsePlugins.get().getFilesDir(true);
67-
ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles);
68-
assert !migratedFiles.isEmpty();
69-
}
70-
71-
@Test
72-
public void autoMigrationBeforeAccessCacheDir() {
73-
prepareForMockFilesWriting();
74-
writtenFiles.addAll(writeSomeMockFiles(false));
75-
ArrayList<File> migratedCaches = new ArrayList<>();
76-
//Auto migration
77-
File cacheDir = ParsePlugins.get().getCacheDir(true);
78-
ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches);
79-
assert !migratedCaches.isEmpty();
80-
}
81-
82-
@Test
83-
public void autoMigrationBeforeAccessCacheOrFilesDirBySolvingFileConflicts() {
84-
prepareForMockFilesWriting();
85-
//Set some existing files in new location so that there could be file conflict.
86-
writtenFiles.addAll(writeSomeMockFiles(true));
87-
88-
//Auto migration for files
89-
ArrayList<File> migratedFiles = new ArrayList<>();
90-
File filesDir = ParsePlugins.get().getFilesDir(true);
91-
ParseFileUtils.getAllNestedFiles(filesDir.getAbsolutePath(), migratedFiles);
92-
93-
/*
94-
Auto migration for caches.
95-
Although migration already completed when accessed `ParsePlugins.get().getFilesDir(true)` or `ParsePlugins.get().getCacheDir(true)` API.
96-
*/
97-
ArrayList<File> migratedCaches = new ArrayList<>();
98-
File cacheDir = ParsePlugins.get().getCacheDir(true);
99-
ParseFileUtils.getAllNestedFiles(cacheDir.getAbsolutePath(), migratedCaches);
100-
101-
assert !migratedFiles.isEmpty();
102-
assert !migratedCaches.isEmpty();
103-
}
104-
10572
private void prepareForMockFilesWriting() {
10673
//Delete `"app_Parse"` dir including nested dir and files.
107-
ParsePlugins.get().deleteOldParseDirSilently();
74+
try {
75+
ParseFileUtils.deleteDirectory(InstrumentationRegistry.getInstrumentation().getContext().getDir("Parse", Context.MODE_PRIVATE));
76+
} catch (Exception e) {
77+
e.printStackTrace();
78+
}
10879
writtenFiles.clear();
10980
//Create new `"app_Parse"` dir to write some files.
110-
createFileDir(ParsePlugins.get().getCacheDir());
81+
createFileDir(InstrumentationRegistry.getInstrumentation().getContext().getCacheDir());
11182
}
11283

11384
private ArrayList<File> writeSomeMockFiles(Boolean checkForExistingFile) {
11485
ArrayList<File> fileToReturn = new ArrayList<>();
115-
File oldRef = ParsePlugins.get().getOldParseDir();
86+
File oldRef = InstrumentationRegistry.getInstrumentation().getContext().getDir("Parse", Context.MODE_PRIVATE);
11687

11788
//Writing some config & random files for migration process.
11889
File config = new File(oldRef + "/config/", "config");
@@ -147,7 +118,7 @@ private ArrayList<File> writeSomeMockFiles(Boolean checkForExistingFile) {
147118
//To create a file conflict scenario during migration by creating an existing file to the new files dir ("*/files/com.parse/*").
148119
if (checkForExistingFile) {
149120
try {
150-
ParseFileUtils.writeStringToFile(new File(ParsePlugins.get().getFilesDir() + "/CommandCache/", "installationId"), "gger", "UTF-8");
121+
ParseFileUtils.writeStringToFile(new File(InstrumentationRegistry.getInstrumentation().getContext().getFilesDir() + "/com.parse/CommandCache/", "installationId"), "gger", "UTF-8");
151122
} catch (Exception e) {
152123
e.printStackTrace();
153124
}

0 commit comments

Comments
 (0)