Skip to content

Commit

Permalink
Merge pull request #29 from CodemateLtd/feature-cache-users
Browse files Browse the repository at this point in the history
Caching users
  • Loading branch information
roughike committed Feb 6, 2017
2 parents 5da2169 + 6697790 commit fa937a9
Show file tree
Hide file tree
Showing 40 changed files with 782 additions and 429 deletions.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,16 @@

package com.codemate.koffeemate.data.local

import com.codemate.koffeemate.data.local.models.CoffeeBrewingEvent
import com.codemate.koffeemate.data.models.CoffeeBrewingEvent
import com.codemate.koffeemate.data.models.User
import io.realm.Realm
import io.realm.RealmConfiguration
import org.hamcrest.core.IsEqual.equalTo
import org.junit.Assert.assertThat
import org.junit.Before
import org.junit.Test

class RealmCoffeeEventRepositoryTest {
class CoffeeEventRepositoryTest {
lateinit var coffeeEventRepository: RealmCoffeeEventRepository

@Before
Expand All @@ -51,9 +52,9 @@ class RealmCoffeeEventRepositoryTest {

@Test
fun recordBrewingEvent_WithUserId_SavesUserId() {
coffeeEventRepository.recordBrewingEvent("abc123")
coffeeEventRepository.recordBrewingEvent(User(id = "abc123"))

assertThat(coffeeEventRepository.getLastBrewingEvent()!!.userId, equalTo("abc123"))
assertThat(coffeeEventRepository.getLastBrewingEvent()!!.user!!.id, equalTo("abc123"))
}

@Test
Expand All @@ -68,35 +69,35 @@ class RealmCoffeeEventRepositoryTest {
@Test
fun getLastBrewingEvent_WhenHavingAccidentsAndSuccessfulEvents_ReturnsOnlyLastBrewingEvent() {
val lastSuccessfulEvent = coffeeEventRepository.recordBrewingEvent()
coffeeEventRepository.recordBrewingAccident("test")
coffeeEventRepository.recordBrewingAccident(User())

assertThat(coffeeEventRepository.getLastBrewingEvent(), equalTo(lastSuccessfulEvent))
}

@Test
fun getLastBrewingAccident_ReturnsLastBrewingAccident() {
val userId = "abc123"
coffeeEventRepository.recordBrewingAccident(userId)
coffeeEventRepository.recordBrewingAccident(userId)
val user = User(id = "abc123")
coffeeEventRepository.recordBrewingAccident(user)
coffeeEventRepository.recordBrewingAccident(user)

val lastAccident = coffeeEventRepository.recordBrewingAccident(userId)
val lastAccident = coffeeEventRepository.recordBrewingAccident(user)
assertThat(coffeeEventRepository.getLastBrewingAccident(), equalTo(lastAccident))
}

@Test
fun getAccidentCountForUser_ReturnsAccidentCountForThatSpecificUser() {
val userId = "abc123"
assertThat(coffeeEventRepository.getAccidentCountForUser(userId), equalTo(0L))
val user = User(id = "abc123")
assertThat(coffeeEventRepository.getAccidentCountForUser(user), equalTo(0L))

coffeeEventRepository.recordBrewingAccident(userId)
coffeeEventRepository.recordBrewingAccident(userId)
coffeeEventRepository.recordBrewingAccident(userId)
coffeeEventRepository.recordBrewingAccident(user)
coffeeEventRepository.recordBrewingAccident(user)
coffeeEventRepository.recordBrewingAccident(user)

val otherUserId = "someotherid"
coffeeEventRepository.recordBrewingAccident(otherUserId)
coffeeEventRepository.recordBrewingAccident(otherUserId)
val otherUser = User(id = "someotherid")
coffeeEventRepository.recordBrewingAccident(otherUser)
coffeeEventRepository.recordBrewingAccident(otherUser)

assertThat(coffeeEventRepository.getAccidentCountForUser(userId), equalTo(3L))
assertThat(coffeeEventRepository.getAccidentCountForUser(user), equalTo(3L))
}

private fun coffeeEventCount() =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2017 Codemate Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.codemate.koffeemate.data.local

import android.content.Context
import android.support.test.InstrumentationRegistry
import com.codemate.koffeemate.data.models.CoffeeBrewingEvent
import io.realm.Realm
import io.realm.RealmConfiguration
import org.hamcrest.core.IsEqual.equalTo
import org.hamcrest.core.IsNull.nullValue
import org.junit.Assert.assertThat
import org.junit.Before
import org.junit.Test
import java.io.File
import java.io.IOException

class MigrationTest {
lateinit var context: Context

@Before
fun setUp() {
context = InstrumentationRegistry.getContext()
}

/*************************************************************
* Migration tests from schema version 0 to 1
*************************************************************/
@Test
fun testMigrationFromVersionZeroToOne() {
val config = RealmConfiguration.Builder()
.name("migration-test.realm")
.schemaVersion(1)
.migration(Migration())
.build()

// The "sample-db-schema-v0.realm" contains three sample records,
// in the old database schema, which used userIds instead of User
// objects.
copyRealmFromAssets(context, "sample-db-schema-v0.realm", config)
val realm = Realm.getInstance(config)

val all = realm.where(CoffeeBrewingEvent::class.java).findAll()
assertThat(all.size, equalTo(3))

val brewingEventWithoutUserId = all[0]
assertThat(brewingEventWithoutUserId.id, equalTo("adf9c9b9-e521-462f-9d67-ff2a11d7b62c"))
assertThat(brewingEventWithoutUserId.time, equalTo(1485872637115L))
assertThat(brewingEventWithoutUserId.isSuccessful, equalTo(true))
assertThat(brewingEventWithoutUserId.user, nullValue())

val brewingEventWithUserId = all[1]
assertThat(brewingEventWithUserId.id, equalTo("0e742762-7181-4bc0-b7b5-d1ff68991dd6"))
assertThat(brewingEventWithUserId.time, equalTo(1485872637117L))
assertThat(brewingEventWithUserId.isSuccessful, equalTo(true))
assertThat(brewingEventWithUserId.user!!.id, equalTo("abc-123"))
assertThat(brewingEventWithUserId.user!!.last_updated, equalTo(0L))

val brewingAccident = all[2]
assertThat(brewingAccident.id, equalTo("480bb3b9-a01f-45cb-87cd-113465d4038a"))
assertThat(brewingAccident.time, equalTo(1485872637118L))
assertThat(brewingAccident.isSuccessful, equalTo(false))
assertThat(brewingAccident.user!!.id, equalTo("abc-123"))
assertThat(brewingEventWithUserId.user!!.last_updated, equalTo(0L))

// Make sure we don't generate different timestamps for the users in
// this new schema.
assertThat(brewingEventWithUserId.user!!.last_updated, equalTo(brewingAccident.user!!.last_updated))

realm.close()
}

@Throws(IOException::class)
fun copyRealmFromAssets(context: Context, realmPath: String, config: RealmConfiguration) {
Realm.deleteRealm(config)

context.assets.open(realmPath).use { inputStream ->
val outFile = File(config.realmDirectory, config.realmFileName)

outFile.outputStream().use { outputStream ->
inputStream.copyTo(outputStream)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
* Copyright 2017 Codemate Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.codemate.koffeemate.data.local

import com.codemate.koffeemate.data.models.User
import io.realm.Realm
import io.realm.RealmConfiguration
import org.hamcrest.core.IsEqual.equalTo
import org.junit.Assert.assertThat
import org.junit.Before
import org.junit.Test

class UserRepositoryTest {
val TEST_USERS_UNIQUE = listOf(User(id = "abc123"), User(id = "123abc"), User(id = "a1b2c3"))
val TEST_USERS_DUPLICATE = listOf(User(id = "abc123"), User(id = "abc123"), User(id = "abc123"))

lateinit var userRepository: UserRepository

@Before
fun setUp() {
val realmConfig = RealmConfiguration.Builder()
.name("test.realm")
.inMemory()
.build()

Realm.setDefaultConfiguration(realmConfig)
Realm.getDefaultInstance().executeTransaction(Realm::deleteAll)

userRepository = RealmUserRepository()
}

@Test
fun addAll_WhenUsersAreUnique_PersistsAllInDatabase() {
userRepository.addAll(TEST_USERS_UNIQUE)

val all = userRepository.getAll()
assertThat(all[0].id, equalTo(TEST_USERS_UNIQUE[0].id))
assertThat(all[1].id, equalTo(TEST_USERS_UNIQUE[1].id))
assertThat(all[2].id, equalTo(TEST_USERS_UNIQUE[2].id))
}

@Test
fun addAll_WhenUsersAreDuplicate_PersistsOnlyOne() {
userRepository.addAll(TEST_USERS_DUPLICATE)

val all = userRepository.getAll()
assertThat(all.size, equalTo(1))
}

@Test
fun addAll_WhenTryingToAddExistingUser_UpdatesIt() {
userRepository.addAll(listOf(User(id = "abc123", name = "John Smith")))
assertThat(userRepository.getAll().first().name, equalTo("John Smith"))

userRepository.addAll(listOf(User(id = "abc123", name = "Kevin Doe")))

val all = userRepository.getAll()
assertThat(all.size, equalTo(1))
assertThat(all.first().name, equalTo("Kevin Doe"))
}
}
4 changes: 0 additions & 4 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@
</intent-filter>
</activity>

<activity
android:name="com.codemate.koffeemate.ui.userselector.UserSelectorActivity"
android:screenOrientation="sensorLandscape"/>

<activity
android:name="com.codemate.koffeemate.ui.settings.SettingsActivity"
android:theme="@style/AppTheme.Settings"/>
Expand Down
15 changes: 14 additions & 1 deletion app/src/main/java/com/codemate/koffeemate/KoffeemateApp.kt
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package com.codemate.koffeemate

import android.app.Application
import com.codemate.koffeemate.data.local.Migration
import com.codemate.koffeemate.data.network.SlackApi
import com.codemate.koffeemate.di.components.AppComponent
import com.codemate.koffeemate.di.components.DaggerAppComponent
import com.codemate.koffeemate.di.modules.AppModule
import com.codemate.koffeemate.di.modules.NetModule
import io.realm.Realm
import io.realm.RealmConfiguration

class KoffeemateApp : Application() {
companion object {
Expand All @@ -16,10 +18,21 @@ class KoffeemateApp : Application() {
override fun onCreate() {
super.onCreate()

Realm.init(this)
initializeRealm()

appComponent = DaggerAppComponent.builder()
.appModule(AppModule(this))
.netModule(NetModule(SlackApi.BASE_URL))
.build()
}

private fun initializeRealm() {
Realm.init(this)

val configuration = RealmConfiguration.Builder()
.migration(Migration())
.schemaVersion(1)
.build()
Realm.setDefaultConfiguration(configuration)
}
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,73 @@
package com.codemate.koffeemate.data.local

import com.codemate.koffeemate.data.local.models.CoffeeBrewingEvent
import com.codemate.koffeemate.data.models.CoffeeBrewingEvent
import com.codemate.koffeemate.data.models.User
import io.realm.Realm
import io.realm.Sort
import java.util.*

interface CoffeeEventRepository {
fun recordBrewingEvent(userId: String? = ""): CoffeeBrewingEvent
fun recordBrewingAccident(userId: String): CoffeeBrewingEvent
fun getAccidentCountForUser(userId: String): Long
fun recordBrewingEvent(user: User? = null): CoffeeBrewingEvent
fun recordBrewingAccident(user: User): CoffeeBrewingEvent
fun getAccidentCountForUser(user: User): Long

fun getLastBrewingEvent(): CoffeeBrewingEvent?
fun getLastBrewingAccident(): CoffeeBrewingEvent?
}

class RealmCoffeeEventRepository : CoffeeEventRepository {
override fun recordBrewingEvent(user: User?) = with(Realm.getDefaultInstance()) {
var event: CoffeeBrewingEvent? = null
executeTransaction {
event = newEvent(it).apply {
time = System.currentTimeMillis()
isSuccessful = true
this.user = if (user != null) copyToRealmOrUpdate(user) else null
}
}

close()
return@with event!!
}

override fun recordBrewingAccident(user: User) = with(Realm.getDefaultInstance()) {
var event: CoffeeBrewingEvent? = null
executeTransaction {
event = newEvent(it).apply {
time = System.currentTimeMillis()
isSuccessful = false
this.user = copyToRealmOrUpdate(user)
}
}

close()
return@with event!!
}

override fun getAccidentCountForUser(user: User) =
Realm.getDefaultInstance()
.where(CoffeeBrewingEvent::class.java)
.equalTo("isSuccessful", false)
.equalTo("user.id", user.id)
.count()

override fun getLastBrewingEvent() =
Realm.getDefaultInstance()
.where(CoffeeBrewingEvent::class.java)
.equalTo("isSuccessful", true)
.findAllSorted("time", Sort.ASCENDING)
.lastOrNull()

override fun getLastBrewingAccident() =
Realm.getDefaultInstance()
.where(CoffeeBrewingEvent::class.java)
.equalTo("isSuccessful", false)
.findAllSorted("time", Sort.ASCENDING)
.lastOrNull()

private fun newEvent(realm: Realm) =
realm.createObject(
CoffeeBrewingEvent::class.java,
UUID.randomUUID().toString()
)
}
Loading

0 comments on commit fa937a9

Please sign in to comment.