Skip to content

Commit b49e7d9

Browse files
authored
Permission API's (#4558)
Add PermissionManager as a convenience API on top of the __permission and __management realms. This PR adds support for - Listing permissions - Changing permissions - Creating offers - Accepting offers - Revoking offers
1 parent e26cd4c commit b49e7d9

41 files changed

Lines changed: 4203 additions & 127 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
11
## 3.7.0 (YYYY-MM-DD)
22

3+
### Deprecated
4+
5+
* [ObjectServer] `SyncUser.getManagementRealm()`. Use `SyncUser.getPermissionManager()` instead.
6+
7+
### Enhancements
8+
9+
* [ObjectServer] `SyncUser.getPermissionManager` added as a helper API for working with permissions and permission offers.
10+
11+
### Internal
12+
13+
* [ObjectServer] Upgraded OkHttp to 3.7.0.
14+
315

416
## 3.6.0 (2017-09-01)
517

@@ -27,6 +39,28 @@ and `SyncUser#retrieveInfoForUserAsync` which returns a `SyncUserInfo` with mode
2739

2840
### Bug Fixes
2941

42+
### Internal
43+
44+
* [ObjectServer] removed `ObjectServerUser` and its inner classes, in a step to reduce `SyncUser` complexity (#3741).
45+
* [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).
46+
* Upgraded Realm Sync to 1.10.8
47+
* Let Object Store handle migration.
48+
49+
## 3.5.1 (YYYY-MM-DD)
50+
51+
### Bug Fixes
52+
53+
### Internal
54+
55+
* [ObjectServer] removed `ObjectServerUser` and its inner classes, in a step to reduce `SyncUser` complexity (#3741).
56+
* [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).
57+
* [ObjectServer] Upgraded Realm Sync to 1.10.8.
58+
* Let Object Store handle migrations and schema validation.
59+
60+
## 3.5.1 (YYYY-MM-DD)
61+
62+
### Bug Fixes
63+
3064
* Potential crash after using `Realm.getSchema()` to change the schema of a typed Realm. `Realm.getSchema()` now returns an immutable `RealmSchema` instance.
3165
* `Realm.copyToRealmOrUpdate()` might cause a `RealmList` field to contain duplicated elements (#4957).
3266
* `RealmSchema.create(String)` and `RealmObjectSchema.setClassName(String)` did not accept class name whose length was 51 to 57.
@@ -157,6 +191,7 @@ and `SyncUser#retrieveInfoForUserAsync` which returns a `SyncUserInfo` with mode
157191
### Enhancements
158192

159193
* [ObjectServer] Added support for `SyncUser.isAdmin()` (#4353).
194+
* [ObjectServer] New set of Permission API's have been added to `SyncUser` through `SyncUser.getPermissionManager()` (#4296).
160195
* [ObjectServer] Added support for changing passwords through `SyncUser.changePassword()` (#4423).
161196
* [ObjectServer] Added support for `SyncConfiguration.Builder.waitForInitialRemoteData()` (#4270).
162197
* Transient fields are now allowed in model classes, but are implicitly treated as having the `@Ignore` annotation (#4279).

realm/config/findbugs/findbugs-filter.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,5 +21,8 @@
2121
<Match>
2222
<Class name="io.realm.PermissionOfferResponseRealmProxy"/>
2323
</Match>
24+
<Match>
25+
<Class name="io.realm.PermissionRealmProxy"/>
26+
</Match>
2427

2528
</FindBugsFilter>

realm/realm-library/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,7 +180,7 @@ dependencies {
180180
implementation 'com.getkeepsafe.relinker:relinker:1.2.2'
181181

182182
kaptObjectServer project(':realm-annotations-processor')
183-
objectServerImplementation 'com.squareup.okhttp3:okhttp:3.4.1'
183+
objectServerImplementation 'com.squareup.okhttp3:okhttp:3.7.0'
184184

185185
kaptAndroidTest project(':realm-annotations-processor')
186186
androidTestImplementation fileTree(dir: 'testLibs', include: ['*.jar'])

realm/realm-library/src/androidTest/java/io/realm/TestHelper.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import java.util.Date;
4040
import java.util.Locale;
4141
import java.util.Random;
42+
import java.util.UUID;
4243
import java.util.concurrent.CountDownLatch;
4344
import java.util.concurrent.ExecutorService;
4445
import java.util.concurrent.TimeUnit;
@@ -319,6 +320,13 @@ public static byte[] getRandomKey() {
319320
return key;
320321
}
321322

323+
public static String getRandomEmail() {
324+
StringBuilder sb = new StringBuilder(UUID.randomUUID().toString().toLowerCase());
325+
sb.append('@');
326+
sb.append("androidtest.realm.io");
327+
return sb.toString();
328+
}
329+
322330
// Returns a random key from the given seed. Used by encrypted Realms.
323331
public static byte[] getRandomKey(long seed) {
324332
byte[] key = new byte[64];
@@ -1134,7 +1142,7 @@ public static void waitRealmThreadExecutorFinish() {
11341142
}
11351143
counter--;
11361144
}
1137-
fail("'BaseRealm.asyncTaskExecutor' is not finished in " + counter/10 + " seconds");
1145+
fail("'BaseRealm.asyncTaskExecutor' is not finished in " + counter/10.0D + " seconds");
11381146
}
11391147

11401148
/**

realm/realm-library/src/androidTest/java/io/realm/rule/RunInLooperThread.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,9 @@ public class RunInLooperThread extends TestRealmConfigurationFactory {
6262
// Thread safe
6363
private final CountDownLatch signalTestCompleted = new CountDownLatch(1);
6464

65+
// Thread safe
66+
private boolean ruleBeingUsed = false;
67+
6568
// Access guarded by 'lock'
6669
private RealmConfiguration realmConfiguration;
6770

@@ -298,6 +301,9 @@ public Statement apply(Statement base, Description description) {
298301
if (annotation == null) {
299302
return base;
300303
}
304+
synchronized (lock) {
305+
ruleBeingUsed = true;
306+
}
301307
return new RunInLooperThreadStatement(annotation, base);
302308
}
303309

@@ -348,6 +354,13 @@ public boolean isTestComplete() {
348354
}
349355
}
350356

357+
/**
358+
* Returns true if the current test being run is using this rule.
359+
*/
360+
public boolean isRuleUsed() {
361+
return ruleBeingUsed;
362+
}
363+
351364
/**
352365
* If an implementation of this is supplied with the annotation, the {@link RunnableBefore#run(RealmConfiguration)}
353366
* will be executed before the looper thread starts. It is normally for populating the Realm before the test.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
* Copyright 2017 Realm Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package io.realm;
18+
19+
import android.support.test.runner.AndroidJUnit4;
20+
21+
import org.junit.Test;
22+
import org.junit.runner.RunWith;
23+
24+
import io.realm.permissions.AccessLevel;
25+
import io.realm.permissions.PermissionRequest;
26+
import io.realm.permissions.UserCondition;
27+
28+
import static org.junit.Assert.assertEquals;
29+
import static org.junit.Assert.assertTrue;
30+
import static org.junit.Assert.fail;
31+
32+
33+
@RunWith(AndroidJUnit4.class)
34+
public class PermissionRequestTests {
35+
36+
@Test
37+
public void nullArgumentsThrows() {
38+
try {
39+
new PermissionRequest(null, "*", AccessLevel.ADMIN);
40+
fail();
41+
} catch (IllegalArgumentException e) {
42+
assertTrue(e.getMessage().contains("Non-null 'condition' required."));
43+
}
44+
45+
try {
46+
new PermissionRequest(UserCondition.userId("id"), null, AccessLevel.ADMIN);
47+
fail();
48+
} catch (IllegalArgumentException e) {
49+
assertTrue(e.getMessage().contains("Non-empty 'realmUrl' required."));
50+
}
51+
52+
try {
53+
new PermissionRequest(UserCondition.userId("id"), "*", null);
54+
fail();
55+
} catch (IllegalArgumentException e) {
56+
assertTrue(e.getMessage().contains("Non-null 'accessLevel' required."));
57+
}
58+
}
59+
60+
@Test
61+
public void url_throwsOnInvalidURIs() {
62+
String[] invalidUrls = { "", "\\", "<foo>" };
63+
for (String url : invalidUrls) {
64+
try {
65+
new PermissionRequest(UserCondition.userId("id"), url, AccessLevel.ADMIN);
66+
fail(url + " should have thrown");
67+
} catch (IllegalArgumentException ignore) {
68+
}
69+
}
70+
}
71+
72+
@Test
73+
public void url_validURIs() {
74+
// We support "*" and valid URI's
75+
// We don't attempt to do more validation than that and leaves that up to ROS
76+
String[] validUrls = {
77+
"*",
78+
"http://foo/bar/baz",
79+
"https://foo/bar/baz",
80+
"realm://foo.bar/~/default",
81+
"realms://foo.bar/~/default"
82+
};
83+
for (String url : validUrls) {
84+
PermissionRequest request = new PermissionRequest(UserCondition.userId("id"), url, AccessLevel.ADMIN);
85+
assertEquals(url, request.getUrl());
86+
}
87+
}
88+
89+
@Test
90+
public void getters() {
91+
UserCondition condition = UserCondition.userId("id");
92+
String url = "*";
93+
AccessLevel accessLevel = AccessLevel.ADMIN;
94+
95+
PermissionRequest request = new PermissionRequest(condition, url, accessLevel);
96+
97+
assertEquals(condition, request.getCondition());
98+
assertEquals(url, request.getUrl());
99+
assertEquals(accessLevel, request.getAccessLevel());
100+
}
101+
102+
@Test
103+
public void equals() {
104+
PermissionRequest r1 = new PermissionRequest(UserCondition.userId("id"), "*", AccessLevel.ADMIN);
105+
PermissionRequest r2 = new PermissionRequest(UserCondition.userId("id"), "*", AccessLevel.ADMIN);
106+
107+
assertTrue(r1.equals(r2));
108+
assertTrue(r2.equals(r1));
109+
assertEquals(r1.hashCode(), r2.hashCode());
110+
}
111+
112+
}

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

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,13 @@
2121
import android.support.test.runner.AndroidJUnit4;
2222

2323
import org.junit.Before;
24+
import org.junit.Ignore;
2425
import org.junit.Rule;
2526
import org.junit.Test;
2627
import org.junit.runner.RunWith;
2728

29+
import java.util.concurrent.atomic.AtomicReference;
30+
2831
import io.realm.rule.RunInLooperThread;
2932
import io.realm.rule.RunTestInLooperThread;
3033
import io.realm.rule.TestSyncConfigurationFactory;
@@ -188,6 +191,56 @@ public void onError(SyncSession session, ObjectServerError error) {
188191
SyncManager.simulateClientReset(SyncManager.getSession(config));
189192
}
190193

194+
// Check that if we manually trigger a Client Reset, then it should be possible to start
195+
// downloading the Realm immediately after.
196+
@Test
197+
@RunTestInLooperThread
198+
@Ignore("https://github.com/realm/realm-java/issues/5143")
199+
public void clientReset_manualTriggerAllowSessionToRestart() {
200+
SyncUser user = createTestUser();
201+
String url = "realm://objectserver.realm.io/~/myrealm";
202+
final AtomicReference<SyncConfiguration> configRef = new AtomicReference<>(null);
203+
final SyncConfiguration config = configFactory.createSyncConfigurationBuilder(user , url)
204+
.errorHandler(new SyncSession.ErrorHandler() {
205+
@Override
206+
public void onError(SyncSession session, ObjectServerError error) {
207+
final ClientResetRequiredError handler = (ClientResetRequiredError) error;
208+
209+
// Execute Client Reset
210+
looperThread.closeTestRealms();
211+
handler.executeClientReset();
212+
213+
// Try to re-open Realm and download it again
214+
looperThread.postRunnable(new Runnable() {
215+
@Override
216+
public void run() {
217+
// Validate that files have been moved
218+
assertFalse(handler.getOriginalFile().exists());
219+
assertTrue(handler.getBackupFile().exists());
220+
221+
SyncConfiguration config = configRef.get();
222+
Realm instance = Realm.getInstance(config);
223+
looperThread.addTestRealm(instance);
224+
try {
225+
SyncManager.getSession(config).downloadAllServerChanges();
226+
looperThread.testComplete();
227+
} catch (InterruptedException e) {
228+
fail(e.toString());
229+
}
230+
}
231+
});
232+
}
233+
})
234+
.build();
235+
configRef.set(config);
236+
237+
Realm realm = Realm.getInstance(config);
238+
looperThread.addTestRealm(realm);
239+
240+
// Trigger error
241+
SyncManager.simulateClientReset(SyncManager.getSession(config));
242+
}
243+
191244
@Test
192245
@UiThreadTest
193246
public void uploadAllLocalChanges_throwsOnUiThread() throws InterruptedException {

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

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import android.support.test.runner.AndroidJUnit4;
2020

21+
import org.junit.After;
2122
import org.junit.Before;
2223
import org.junit.Rule;
2324
import org.junit.Test;
@@ -26,7 +27,9 @@
2627

2728
import java.io.IOException;
2829
import java.util.Collection;
30+
import java.util.Collections;
2931

32+
import io.realm.objectserver.utils.UserFactory;
3033
import io.realm.rule.TestRealmConfigurationFactory;
3134

3235
import static io.realm.util.SyncTestUtils.createTestUser;
@@ -66,7 +69,7 @@ public void remove(String identity, String authenticationUrl) {
6669

6770
@Override
6871
public Collection<SyncUser> allUsers() {
69-
return null;
72+
return Collections.emptySet();
7073
}
7174

7275
@Override
@@ -76,6 +79,12 @@ public boolean isActive(String identity, String authenticationUrl) {
7679
};
7780
}
7881

82+
@After
83+
public void tearDown() {
84+
UserFactory.logoutAllUsers();
85+
SyncManager.reset();
86+
}
87+
7988
@Test
8089
public void set_userStore() {
8190
SyncManager.setUserStore(userStore);

0 commit comments

Comments
 (0)