Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[RKOTLIN-1083] Remove deprecated user methods #1750

Merged
merged 11 commits into from
May 21, 2024
1 change: 1 addition & 0 deletions .github/actions/run-android-device-farm-test/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ runs:
test_spec_file: test_spec-${{ inputs.app-id }}.yaml
test_spec_type: APPIUM_PYTHON_TEST_SPEC
remote_src: true
timeout: 3600
test_spec: |
version: 0.1
phases:
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ This release will bump the Realm file format from version 23 to 24. Opening a fi
### Breaking changes
* Removed property `RealmLog.level`. Log levels can be set with `RealmLog.setLevel`. (Issue [#1691](https://github.com/realm/realm-kotlin/issues/1691) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1038))
* Removed `LogConfiguration`. Log levels and custom loggers can be set with `RealmLog`. (Issue [#1691](https://github.com/realm/realm-kotlin/issues/1691) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1038))
* Removed deprecated methods `User.identity` and `User.provider`, user identities can be accessed with the already existing `User.identities`. (Issue [#1751](https://github.com/realm/realm-kotlin/issues/1751) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1083))
* `App.allUsers` does no longer return a map, but only a list of users known locally. (Issue [#1751](https://github.com/realm/realm-kotlin/issues/1751) [JIRA](https://jira.mongodb.org/browse/RKOTLIN-1083))

### Enhancements
* Support for RealmLists and RealmDictionaries in `RealmAny`. (Issue [#1434](https://github.com/realm/realm-kotlin/issues/1434))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,9 @@ public interface App {
* Returns all known users that are either [User.State.LOGGED_IN] or [User.State.LOGGED_OUT].
* Only users that at some point logged into this device will be returned.
*
* @return a map of user identifiers and users known locally. User identifiers will match what
* is returned by [User.identity].
* @return a list of locally known users.
*/
public fun allUsers(): Map<String, User>
public fun allUsers(): List<User>

/**
* Log in as a user with the given credentials associated with an authentication provider.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,14 +52,6 @@ public interface User {
*/
public val state: State

/**
* The server id of the user.
*
* This property has been deprecated in favor of [id] and will be replaced in a future release.
*/
@Deprecated("Use `User.id` instead", replaceWith = ReplaceWith("id"))
public val identity: String

/**
* The server id of the user.
*/
Expand All @@ -79,13 +71,6 @@ public interface User {
*/
public val identities: List<UserIdentity>

/**
* Returns the provider type used to log the user in.
* If a user logs out, the authentication provider last used to log the user in will still be returned.
*/
@Deprecated("Users might have multiple providers. This will return the provider of the first identity of the user", ReplaceWith("identities"))
public val provider: AuthenticationProvider

/**
* Returns the current access token for the user.
* If a user logs out, an empty access token is returned.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,11 @@ public class AppImpl(
?.let { UserImpl(it, this) }
override val sync: Sync by lazy { SyncImpl(nativePointer) }

override fun allUsers(): Map<String, User> {
val nativeUsers: List<RealmUserPointer> =
RealmInterop.realm_app_get_all_users(nativePointer)
val map = mutableMapOf<String, User>()
nativeUsers.map { ptr: RealmUserPointer ->
val user = UserImpl(ptr, this)
map[user.identity] = user
}
return map
}
override fun allUsers(): List<User> =
RealmInterop.realm_app_get_all_users(nativePointer)
.map { ptr: RealmUserPointer ->
UserImpl(ptr, this)
}

override suspend fun login(credentials: Credentials): User {
// suspendCoroutine doesn't allow freezing callback capturing continuation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ import io.realm.kotlin.internal.interop.RealmInterop
import io.realm.kotlin.internal.interop.RealmUserPointer
import io.realm.kotlin.internal.interop.sync.CoreUserState
import io.realm.kotlin.internal.util.use
import io.realm.kotlin.mongodb.AuthenticationProvider
import io.realm.kotlin.mongodb.Credentials
import io.realm.kotlin.mongodb.Functions
import io.realm.kotlin.mongodb.User
Expand All @@ -41,16 +40,11 @@ public class UserImpl(
override val state: User.State
get() = fromCoreState(RealmInterop.realm_user_get_state(nativePointer))

// TODO Can maybe fail, but we could also cache the return value?
override val identity: String
get() = id
override val id: String
get() = RealmInterop.realm_user_get_identity(nativePointer)
override val loggedIn: Boolean
get() = RealmInterop.realm_user_is_logged_in(nativePointer)
@Deprecated("Property not stable, users might have multiple providers.", ReplaceWith("User.identities"))
override val provider: AuthenticationProvider
get() = identities.first().provider

override val accessToken: String
get() = RealmInterop.realm_user_get_access_token(nativePointer)
override val refreshToken: String
Expand Down Expand Up @@ -187,13 +181,13 @@ public class UserImpl(
if (other == null || this::class != other::class) return false

other as UserImpl
if (id != (other.id)) return false

if (identity != (other.identity)) return false
return app.configuration == other.app.configuration
}

override fun hashCode(): Int {
var result = identity.hashCode()
var result = id.hashCode()
result = 31 * result + app.configuration.appId.hashCode()
return result
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ import kotlin.test.assertNotEquals
import kotlin.test.assertNull
import kotlin.test.assertSame
import kotlin.test.assertTrue
import kotlin.test.fail

class AppTests {

Expand Down Expand Up @@ -121,7 +120,7 @@ class AppTests {
@Suppress("LoopWithTooManyJumpStatements")
@Test
fun login_invalidCredentialsThrows() = runBlocking {
for (provider in AuthenticationProvider.values()) {
for (provider in AuthenticationProvider.entries) {
when (provider) {
AuthenticationProvider.ANONYMOUS -> {
// No user input, so invalid credentials are not possible.
Expand Down Expand Up @@ -164,50 +163,51 @@ class AppTests {
@Test
fun allUsers() = runBlocking {
assertEquals(0, app.allUsers().size)

val user1 = app.login(Credentials.anonymous())
var allUsers = app.allUsers()
assertEquals(1, allUsers.size)
assertTrue(allUsers.containsKey(user1.identity))
assertEquals(user1, allUsers[user1.identity])
assertTrue(allUsers.contains(user1))

// Only 1 anonymous user exists, so logging in again just returns the old one
val user2 = app.login(Credentials.anonymous())
allUsers = app.allUsers()
assertEquals(1, allUsers.size)
assertTrue(allUsers.containsKey(user2.identity))
assertTrue(allUsers.contains(user2))

val user3: User = app.asTestApp.createUserAndLogIn(TestHelper.randomEmail(), "123456")
allUsers = app.allUsers()
assertEquals(2, allUsers.size)
assertTrue(allUsers.containsKey(user3.identity))
assertTrue(allUsers.contains(user3))

// Logging out users that registered with email/password will just put them in LOGGED_OUT state
user3.logOut()
allUsers = app.allUsers()
assertEquals(2, allUsers.size)
assertTrue(allUsers.containsKey(user3.identity))
assertEquals(User.State.LOGGED_OUT, allUsers[user3.identity]!!.state)
clementetb marked this conversation as resolved.
Show resolved Hide resolved
assertTrue(allUsers.contains(user3))

// Logging out anonymous users will remove them completely
user1.logOut()
allUsers = app.allUsers()
assertEquals(1, allUsers.size)
assertFalse(allUsers.containsKey(user1.identity))
assertTrue(allUsers.contains(user3))
assertFalse(allUsers.contains(user2))
assertFalse(allUsers.contains(user1))
}

@Test
fun allUsers_retrieveRemovedUser() = runBlocking {
val user1: User = app.login(Credentials.anonymous())
val allUsers: Map<String, User> = app.allUsers()
val allUsers = app.allUsers()
assertEquals(1, allUsers.size)
user1.logOut()
assertEquals(1, allUsers.size)
val userCopy: User = allUsers[user1.identity] ?: fail("Could not find user")
val userCopy: User = allUsers.first()
assertEquals(user1, userCopy)
assertEquals(User.State.REMOVED, userCopy.state)
assertTrue(app.allUsers().isEmpty())
}
//

// @Test
// fun switchUser() {
// val user1: User = app.login(Credentials.anonymous())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ class CredentialsTests {

@Test
fun allCredentials() {
AuthenticationProvider.values().flatMap {
AuthenticationProvider.entries.flatMap {
when (it) {
AuthenticationProvider.ANONYMOUS -> listOf(it to anonymous())
AuthenticationProvider.EMAIL_PASSWORD -> listOf(it to emailPassword())
Expand Down Expand Up @@ -103,7 +103,7 @@ class CredentialsTests {

@Test
fun allCredentials_emptyInputThrows() {
for (value in AuthenticationProvider.values()) {
for (value in AuthenticationProvider.entries) {
assertFailsWith<IllegalArgumentException>("$value failed") { // No arguments should be allow
when (value) {
AuthenticationProvider.ANONYMOUS -> throw IllegalArgumentException("Do nothing, no arguments")
Expand Down Expand Up @@ -267,29 +267,29 @@ class CredentialsTests {
assertNotNull(firstUser)
val reusedUser = app.login(Credentials.anonymous())
assertNotNull(reusedUser)
assertEquals(firstUser.identity, reusedUser.identity)
assertEquals(firstUser, reusedUser)

val newAnonymousUser1 = app.login(Credentials.anonymous(false))
assertNotNull(newAnonymousUser1)
assertNotEquals(firstUser.identity, newAnonymousUser1.identity)
assertNotEquals(firstUser, newAnonymousUser1)

val newAnonymousUser2 = app.login(Credentials.anonymous(false))
assertNotNull(newAnonymousUser2)
assertNotEquals(newAnonymousUser1.identity, newAnonymousUser2.identity)
assertNotEquals(newAnonymousUser1, newAnonymousUser2)
}
}

@Test
fun loginUsingCredentials() {
runBlocking {
AuthenticationProvider.values().forEach { provider ->
AuthenticationProvider.entries.forEach { provider ->
when (provider) {
AuthenticationProvider.ANONYMOUS -> {
val reusableUser = app.login(Credentials.anonymous())
assertNotNull(reusableUser)
val nonReusableUser = app.login(Credentials.anonymous(false))
assertNotNull(nonReusableUser)
assertNotEquals(reusableUser.identity, nonReusableUser.identity)
assertNotEquals(reusableUser, nonReusableUser)
}
AuthenticationProvider.API_KEY -> {
// Log in, create an API key, log out, log in with the key, compare users
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -954,7 +954,7 @@ class FunctionsTests {

@Test
fun unknownFunction() {
assertFailsWithMessage<FunctionExecutionException>("function not found: 'unknown'") {
assertFailsWithMessage<FunctionExecutionException>("function not found") {
runBlocking {
functions.call<String>("unknown", 32)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ class UserTests {
fun getProviderType() = runBlocking {
val email = randomEmail()
val emailUser = createUserAndLogin(email, "123456")
assertEquals(AuthenticationProvider.EMAIL_PASSWORD, emailUser.provider)
assertEquals(AuthenticationProvider.EMAIL_PASSWORD, emailUser.identities.first().provider)
emailUser.logOut()
// AuthenticationProvider is not removed once user is logged out
assertEquals(AuthenticationProvider.EMAIL_PASSWORD, emailUser.provider)
assertEquals(AuthenticationProvider.EMAIL_PASSWORD, emailUser.identities.first().provider)
}

@Test
Expand Down
Loading