Skip to content

Commit 9e31381

Browse files
authored
Merge 5db33bc into master-4.0
2 parents bf535c3 + 5db33bc commit 9e31381

22 files changed

Lines changed: 780 additions & 641 deletions

File tree

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@
2828

2929
## 3.6.0 (YYYY-MM-DD)
3030

31+
### Breaking Changes
32+
33+
* [ObjectServer] `SyncUser.logout()` no longer throws an exception when associated Realms instances are not closed (#4962).
34+
3135
### Deprecated
3236

3337
* [ObjectServer] `SyncUser#retrieveUser` and `SyncUser#retrieveUserAsync` replaced by `SyncUser#retrieveInfoForUser`
@@ -45,6 +49,8 @@ and `SyncUser#retrieveInfoForUserAsync` which returns a `SyncUserInfo` with mode
4549
### Bug Fixes
4650

4751
### Internal
52+
* [ObjectServer] removed `ObjectServerUser` and its inner classes, in a step to reduce `SyncUser` complexity (#3741).
53+
* [ObjectServer] changed the `SyncSessionStopPolicy` to `AfterChangesUploaded` to align with other binding and to prevent use cases where the Realm might be deleted before the last changes get synchronized (#5028).
4854

4955

5056
## 3.5.1 (YYYY-MM-DD)

examples/secureTokenAndroidKeyStore/src/main/java/io/realm/examples/securetokenandroidkeystore/MainActivity.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323

2424
import com.example.securetokenandroidkeystore.R;
2525

26-
import org.json.JSONArray;
2726
import org.json.JSONException;
2827
import org.json.JSONObject;
2928

@@ -35,7 +34,6 @@
3534
import io.realm.SyncManager;
3635
import io.realm.SyncUser;
3736
import io.realm.android.SecureUserStore;
38-
import io.realm.internal.objectserver.ObjectServerUser;
3937
import io.realm.internal.objectserver.Token;
4038

4139
/**
@@ -97,24 +95,16 @@ private void buildSyncConf() {
9795

9896
// Helpers
9997
private final static String USER_TOKEN = UUID.randomUUID().toString();
100-
private final static String REALM_TOKEN = UUID.randomUUID().toString();
10198

10299
private static SyncUser createTestUser(long expires) {
103100
Token userToken = new Token(USER_TOKEN, "JohnDoe", null, expires, null);
104-
Token accessToken = new Token(REALM_TOKEN, "JohnDoe", "/foo", expires, new Token.Permission[]{Token.Permission.DOWNLOAD});
105-
ObjectServerUser.AccessDescription desc = new ObjectServerUser.AccessDescription(accessToken, "/data/data/myapp/files/default", false);
106-
107101
JSONObject obj = new JSONObject();
108102
try {
109-
JSONArray realmList = new JSONArray();
110103
JSONObject realmDesc = new JSONObject();
111104
realmDesc.put("uri", "realm://objectserver.realm.io/default");
112-
realmDesc.put("description", desc.toJson());
113-
realmList.put(realmDesc);
114105

115106
obj.put("authUrl", "http://objectserver.realm.io/auth");
116107
obj.put("userToken", userToken.toJson());
117-
obj.put("realms", realmList);
118108
return SyncUser.fromJson(obj.toString());
119109
} catch (JSONException e) {
120110
throw new RuntimeException(e);

realm/realm-library/src/androidTestObjectServer/java/io/realm/AuthenticateRequestTests.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public void setUp() {
3939

4040
@Test
4141
public void realmLogin() throws URISyntaxException, JSONException {
42-
Token t = SyncTestUtils.createTestUser().getSyncUser().getUserToken();
42+
Token t = SyncTestUtils.createTestUser().getAccessToken();
4343
AuthenticateRequest request = AuthenticateRequest.realmLogin(t, new URI("realm://objectserver/" + t.identity() + "/default"));
4444

4545
JSONObject obj = new JSONObject(request.toJson());
@@ -60,7 +60,7 @@ public void userLogin() throws URISyntaxException, JSONException {
6060

6161
@Test
6262
public void userRefresh() throws URISyntaxException, JSONException {
63-
Token t = SyncTestUtils.createTestUser().getSyncUser().getUserToken();
63+
Token t = SyncTestUtils.createTestUser().getAccessToken();
6464
AuthenticateRequest request = AuthenticateRequest.userRefresh(t, new URI("realm://objectserver/" + t.identity() + "/default"));
6565

6666
JSONObject obj = new JSONObject(request.toJson());

realm/realm-library/src/androidTestObjectServer/java/io/realm/SessionTests.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@
2525
import org.junit.Test;
2626
import org.junit.runner.RunWith;
2727

28-
import io.realm.objectserver.utils.Constants;
29-
import io.realm.objectserver.utils.UserFactory;
3028
import io.realm.rule.RunInLooperThread;
3129
import io.realm.rule.RunTestInLooperThread;
3230
import io.realm.rule.TestSyncConfigurationFactory;

realm/realm-library/src/androidTestObjectServer/java/io/realm/SyncUserTests.java

Lines changed: 125 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,17 +31,25 @@
3131
import org.mockito.invocation.InvocationOnMock;
3232
import org.mockito.stubbing.Answer;
3333

34+
import java.io.File;
35+
import java.lang.reflect.Constructor;
36+
import java.lang.reflect.InvocationTargetException;
37+
import java.net.MalformedURLException;
3438
import java.net.URI;
3539
import java.net.URISyntaxException;
3640
import java.net.URL;
41+
import java.util.Calendar;
42+
import java.util.Iterator;
3743
import java.util.List;
3844
import java.util.Map;
39-
import java.util.Iterator;
4045
import java.util.UUID;
4146

47+
import io.realm.entities.StringOnly;
4248
import io.realm.internal.network.AuthenticateResponse;
4349
import io.realm.internal.network.AuthenticationServer;
50+
import io.realm.internal.objectserver.Token;
4451
import io.realm.log.RealmLog;
52+
import io.realm.objectserver.utils.StringOnlyModule;
4553
import io.realm.rule.RunInLooperThread;
4654
import io.realm.rule.RunTestInLooperThread;
4755
import io.realm.util.SyncTestUtils;
@@ -50,6 +58,7 @@
5058
import static io.realm.util.SyncTestUtils.createTestUser;
5159
import static junit.framework.Assert.assertEquals;
5260
import static org.junit.Assert.assertFalse;
61+
import static org.junit.Assert.assertNotEquals;
5362
import static org.junit.Assert.assertNotNull;
5463
import static org.junit.Assert.assertNull;
5564
import static org.junit.Assert.assertTrue;
@@ -60,6 +69,20 @@
6069
@RunWith(AndroidJUnit4.class)
6170
public class SyncUserTests {
6271

72+
private static final URL authUrl;
73+
private static final Constructor<SyncUser> SYNC_USER_CONSTRUCTOR;
74+
static {
75+
try {
76+
authUrl = new URL("http://localhost/auth");
77+
SYNC_USER_CONSTRUCTOR = SyncUser.class.getDeclaredConstructor(Token.class, URL.class);
78+
SYNC_USER_CONSTRUCTOR.setAccessible(true);
79+
} catch (MalformedURLException e) {
80+
throw new ExceptionInInitializerError(e);
81+
} catch (NoSuchMethodException e) {
82+
throw new ExceptionInInitializerError(e);
83+
}
84+
}
85+
6386
@Rule
6487
public final RunInLooperThread looperThread = new RunInLooperThread();
6588

@@ -81,6 +104,45 @@ public void setUp() {
81104
SyncManager.reset();
82105
}
83106

107+
private static SyncUser createFakeUser(String id) {
108+
final Token token = new Token("token_value", id, "path_value", Long.MAX_VALUE, null);
109+
try {
110+
return SYNC_USER_CONSTRUCTOR.newInstance(token, authUrl);
111+
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
112+
fail(e.getMessage());
113+
}
114+
return null;
115+
}
116+
117+
@Test
118+
public void equals_validUser() {
119+
final SyncUser user1 = createFakeUser("id_value");
120+
final SyncUser user2 = createFakeUser("id_value");
121+
assertTrue(user1.equals(user2));
122+
}
123+
124+
@Test
125+
public void equals_loggedOutUser() {
126+
final SyncUser user1 = createFakeUser("id_value");
127+
final SyncUser user2 = createFakeUser("id_value");
128+
user1.logout();
129+
user2.logout();
130+
assertTrue(user1.equals(user2));
131+
}
132+
133+
@Test
134+
public void hashCode_validUser() {
135+
final SyncUser user = createFakeUser("id_value");
136+
assertNotEquals(0, user.hashCode());
137+
}
138+
139+
@Test
140+
public void hashCode_loggedOutUser() {
141+
final SyncUser user = createFakeUser("id_value");
142+
user.logout();
143+
assertNotEquals(0, user.hashCode());
144+
}
145+
84146
@Test
85147
public void toAndFromJson() {
86148
SyncUser user1 = createTestUser();
@@ -407,4 +469,66 @@ public void allSessions() {
407469
realm2.close();
408470
assertEquals(0, user.allSessions().size());
409471
}
472+
473+
// JSON format changed in 3.6.0 (removed unnecessary fields), this regression test
474+
// makes sure we can still deserialize a valid SyncUser from the old format.
475+
@Test
476+
public void fromJson_WorkWithRemovedObjectServerUser() {
477+
String oldSyncUserJSON = "{\"authUrl\":\"http:\\/\\/192.168.1.151:9080\\/auth\",\"userToken\":{\"token\":\"eyJpZGVudGl0eSI6IjY4OWQ5MGMxNDIyYTIwMmZkNTljNDYwM2M0ZTRmNmNjIiwiZXhwaXJlcyI6MTgxNjM1ODE4NCwiYXBwX2lkIjoiaW8ucmVhbG0ucmVhbG10YXNrcyIsImFjY2VzcyI6WyJyZWZyZXNoIl0sImlzX2FkbWluIjpmYWxzZSwic2FsdCI6MC4yMTEwMjQyNDgwOTEyMzg1NH0=:lEDa83o1zu8rkwdZVpTyunLHh1wmjxPPSGmZQNxdEM7xDmpbiU7V+8dgDWGevJNHMFluNDAOmrcAOI9TLfhI4rMDl70NI1K9rv\\/Aeq5uIOzq\\/Gf7JTeTUKY5Z7yRoppd8NArlNBKesLFxzdLRlfm1hflF9wH23xQXA19yUZ67JIlkhDPL5e3bau8O3Pr\\/St0unW3KzPOiZUk1l9KRrs2iMCCiXCfq4rf6rp7B2M7rBUMQm68GnB1Ot7l1CblxEWcREcbpyhBKTWIOFRGMwg2TW\\/zRR3cRNglx+ZC4FOeO0mfkX+nf+slyFODAnQkOzPZcGO8xc3I1emafX58Wl\\/Guw==\",\"token_data\":{\"identity\":\"689d90c1422a202fd59c4603c4e4f6cc\",\"path\":\"\",\"expires\":1816358184,\"access\":[\"unknown\"],\"is_admin\":false}},\"realms\":[]}";
478+
SyncUser syncUser = SyncUser.fromJson(oldSyncUserJSON);
479+
480+
// Note: we can't call isValid() and expect it to be true
481+
// since the user is not persisted in the UserStore
482+
// isValid() requires SyncManager.getUserStore().isActive(identity)
483+
// to return true as well.
484+
Token accessToken = syncUser.getAccessToken();
485+
assertNotNull(accessToken);
486+
// refresh token should expire in 10 years (July 23, 2027)
487+
Calendar calendar = Calendar.getInstance();
488+
calendar.setTimeInMillis(accessToken.expiresMs());
489+
int day = calendar.get(Calendar.DAY_OF_MONTH);
490+
int month = calendar.get(Calendar.MONTH);
491+
int year = calendar.get(Calendar.YEAR);
492+
493+
assertEquals(23, day);
494+
assertEquals(Calendar.JULY, month);
495+
assertEquals(2027, year);
496+
497+
assertEquals("http://192.168.1.151:9080/auth", syncUser.getAuthenticationUrl().toString());
498+
}
499+
500+
@Test
501+
@Ignore("until https://github.com/realm/realm-java/issues/5097 is fixed")
502+
public void logoutUserShouldDeleteRealmAfterRestart() throws InterruptedException {
503+
SyncManager.reset();
504+
BaseRealm.applicationContext = null; // Required for Realm.init() to work
505+
Realm.init(InstrumentationRegistry.getTargetContext());
506+
507+
SyncUser user = createTestUser();
508+
SyncConfiguration syncConfiguration = new SyncConfiguration
509+
.Builder(user, "realm://127.0.0.1:9080/~/tests")
510+
.modules(new StringOnlyModule())
511+
.build();
512+
513+
Realm realm = Realm.getInstance(syncConfiguration);
514+
realm.executeTransaction(new Realm.Transaction() {
515+
@Override
516+
public void execute(Realm realm) {
517+
realm.createObject(StringOnly.class).setChars("1");
518+
}
519+
});
520+
user.logout();
521+
realm.close();
522+
523+
final File realmPath = new File (syncConfiguration.getPath());
524+
assertTrue(realmPath.exists());
525+
526+
// simulate an app restart
527+
SyncManager.reset();
528+
BaseRealm.applicationContext = null;
529+
Realm.init(InstrumentationRegistry.getTargetContext());
530+
531+
//now the file should be deleted
532+
assertFalse(realmPath.exists());
533+
}
410534
}

realm/realm-library/src/androidTestObjectServer/java/io/realm/internal/objectserver/ObjectServerUserTests.java

Lines changed: 0 additions & 75 deletions
This file was deleted.

0 commit comments

Comments
 (0)