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

Test Firebase better #159

Merged
merged 3 commits into from
Jun 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
203 changes: 170 additions & 33 deletions app/src/androidTest/java/ch/epfl/sweng/rps/FirebaseTests.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,25 @@ package ch.epfl.sweng.rps

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import ch.epfl.sweng.rps.models.remote.Hand
import ch.epfl.sweng.rps.models.remote.*
import ch.epfl.sweng.rps.remote.Env
import ch.epfl.sweng.rps.remote.FirebaseReferences
import ch.epfl.sweng.rps.remote.FirebaseRepository
import ch.epfl.sweng.rps.remote.Repository
import ch.epfl.sweng.rps.services.FirebaseGameService
import ch.epfl.sweng.rps.services.GameService.GameServiceException
import ch.epfl.sweng.rps.services.ProdServiceLocator
import ch.epfl.sweng.rps.services.ServiceLocator
import ch.epfl.sweng.rps.utils.FirebaseEmulatorsUtils
import ch.epfl.sweng.rps.utils.europeWest1
import com.google.android.gms.tasks.Tasks
import com.google.firebase.FirebaseApp
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.firestore.*
import com.google.firebase.firestore.ktx.toObject
import com.google.firebase.ktx.Firebase
import io.mockk.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import org.junit.After
Expand All @@ -33,7 +40,8 @@ import org.junit.runner.RunWith
@ExperimentalCoroutinesApi
@RunWith(AndroidJUnit4::class)
class FirebaseTests {
lateinit var db: Repository
private lateinit var db: Repository


@Before
fun setUp() {
Expand All @@ -49,6 +57,7 @@ class FirebaseTests {
@After
fun tearDown() {
FirebaseApp.clearInstancesForTest()
unmockkAll()
}

@Test
Expand All @@ -65,9 +74,145 @@ class FirebaseTests {
assertEquals(Env.Test, serviceLocatorDev.env)

assertEquals(
serviceLocatorProd.repository,
serviceLocatorProd.repository
serviceLocatorProd.repository, serviceLocatorProd.repository
)
}

inline fun <reified T> mockQuerySnapshot(data: Map<String, Pair<T, Map<String, Any?>>>): QuerySnapshot {
val querySnapshot = mockk<QuerySnapshot>()
every { querySnapshot.toObjects(any<Class<T>>()) } returns data.values.map { it.first }
every { querySnapshot.documents } returns data.map { e ->
mockk<DocumentSnapshot>().apply {
every { [email protected] } returns e.value.second
every { toObject(any<Class<T>>()) } returns e.value.first
every { toObject<T>() } returns e.value.first
every { id } returns e.key
val k = slot<String>()
every { [email protected](capture(k)) } answers {
e.value.second[k.captured]
}
}
}
return querySnapshot
}

inline fun <reified T> mockDocumentSnapshot(
id: String, data: Pair<T, Map<String, Any?>>
): DocumentSnapshot {
val documentSnapshot = mockk<DocumentSnapshot>()
every { documentSnapshot.data } returns data.second
val k = slot<String>()
every { documentSnapshot.get(capture(k)) } answers {
data.second[k.captured]
}
every { documentSnapshot.toObject(any<Class<T>>()) } returns data.first
every { documentSnapshot.toObject<T>() } returns data.first
every { documentSnapshot.id } returns id
return documentSnapshot
}

fun <T> mockTask(value: T) = Tasks.forResult(value)
inline fun <reified T : Any> mockCollection(
id: String, data: Map<String, Pair<T, Map<String, Any?>>>
): CollectionReference {
val mock = mockk<CollectionReference>()
every { mock.get() } returns mockTask(mockQuerySnapshot(data))
every { mock.id } returns id
val identities = listOf<MockKMatcherScope.() -> Query>(
{ mock.whereArrayContains(any<String>(), any()) },
{ mock.whereEqualTo(any<String>(), any()) },
{ mock.whereGreaterThan(any<String>(), any()) },
{ mock.whereGreaterThanOrEqualTo(any<String>(), any()) },
{ mock.whereLessThan(any<String>(), any()) },
{ mock.whereLessThanOrEqualTo(any<String>(), any()) },
{ mock.whereNotEqualTo(any<String>(), any()) },
{ mock.orderBy(any<String>(), any()) },
{ mock.orderBy(any<String>()) },
{ mock.limit(any()) },
)
identities.forEach { every(it) returns mock }
val s = slot<String>()
every { mock.document(capture(s)) } answers {
mockk<DocumentReference>().apply {
every { [email protected] } returns s.captured
every { get() } returns mockTask(mockDocumentSnapshot(s.captured, data[s.captured]!!))
}
}
return mock
}

/*
* class FirebaseReferences {
private val root = FirebaseFirestore.getInstance()
private val storageRoot = FirebaseStorage.getInstance().reference

/**
* Thefriend request collection.
*/
val usersFriendRequest = root.collection("friend_requests")

/**
* Theusers collection.
*/
val usersCollection = root.collection("users")

/**
* Theprofile pictures folder.
*/
val profilePicturesFolder = storageRoot.child("profile_pictures")

/**
* Thegames collection.
*/
val gamesCollection = root.collection("games")

/**
* Thescores collection.
*/
val scoresCollection = root.collection("scores")

/**
* Returns the collection of invitations for the given user
* with [uid].
*/
fun invitationsOfUid(uid: String) = usersCollection
.document(uid)
.collection("invitations")
}
*/
fun mockFirebaseReferences(): FirebaseReferences {
val m = mockk<FirebaseReferences>()
every { m.usersFriendRequest } returns mockCollection(
"friend_requests", mapOf("" to (FriendRequest(users = listOf("me", "you")) to mapOf()))
)
every { m.usersCollection } returns mockCollection("users", mapOf("" to (User() to mapOf())))
every { m.gamesCollection } returns mockCollection(
"games", mapOf(
"rps" to (Game.Rps() to mapOf(
"edition" to GameMode.GameEdition.RockPaperScissors.name,
))
)
)
every { m.scoresCollection } returns mockCollection("scores", mapOf("" to (TotalScore() to mapOf())))
every { m.profilePicturesFolder } returns mockk()
return m
}

@Test
fun testFirebaseRepo(): Unit = runBlocking {
val fb = mockFirebaseReferences()
val auth = mockk<FirebaseAuth>()
every { auth.currentUser } returns mockk<FirebaseUser>().apply { every { uid } returns "me" }
val repo = FirebaseRepository.createInstance(fb, auth)

assertEquals(User(), repo.getUser("").getOrThrow())
assertEquals(Game.Rps(), repo.games.getGame("rps"))
assertEquals(listOf(Game.Rps()), repo.games.gamesOfUser("me"))
assertEquals(listOf(Game.Rps()), repo.games.myActiveGames())
assertEquals(listOf(TotalScore()), repo.games.getLeaderBoardScore(""))
assertEquals("me", repo.getCurrentUid())
assertEquals(listOf(FriendRequest(users = listOf("me", "you"))), repo.friends.listFriendRequests())
assertEquals(listOf("you"), repo.friends.getFriends())
}

@Test
Expand All @@ -76,20 +221,17 @@ class FirebaseTests {
assertEquals("1234", serviceLocatorProd.getGameServiceForGame("1234", start = false).gameId)
assertTrue(
serviceLocatorProd.getGameServiceForGame(
"1",
start = false
"1", start = false
) === serviceLocatorProd.getGameServiceForGame("1", start = false)
)

val service: FirebaseGameService =
serviceLocatorProd.getGameServiceForGame("1234", start = false)
val service: FirebaseGameService = serviceLocatorProd.getGameServiceForGame("1234", start = false)

val throwingActions: List<suspend (service: FirebaseGameService) -> Unit> =
listOf(
{ it.refreshGame() },
{ it.addRound() },
{ it.playHand(Hand.PAPER) },
)
val throwingActions: List<suspend (service: FirebaseGameService) -> Unit> = listOf(
{ it.refreshGame() },
{ it.addRound() },
{ it.playHand(Hand.PAPER) },
)

for (action in throwingActions) {
assertThrows(Exception::class.java) {
Expand All @@ -107,8 +249,7 @@ class FirebaseTests {
@Test
fun disposingGameServices() {
val serviceLocator = ServiceLocator.getInstance(env = Env.Prod) as ProdServiceLocator
val service: FirebaseGameService =
serviceLocator.getGameServiceForGame("1234", start = false)
val service: FirebaseGameService = serviceLocator.getGameServiceForGame("1234", start = false)
assertEquals(listOf("1234"), serviceLocator.cachedGameServices)
assertFalse(service.isDisposed)
serviceLocator.disposeAllGameServices()
Expand All @@ -120,8 +261,7 @@ class FirebaseTests {
fun disposingGameServices2() {
val serviceLocator = ServiceLocator.getInstance(env = Env.Prod) as ProdServiceLocator
serviceLocator.disposeAllGameServices()
val service: FirebaseGameService =
serviceLocator.getGameServiceForGame("1234", start = false)
val service: FirebaseGameService = serviceLocator.getGameServiceForGame("1234", start = false)
assertEquals(listOf("1234"), serviceLocator.cachedGameServices)
assertFalse(service.isDisposed)
service.dispose()
Expand All @@ -134,20 +274,18 @@ class FirebaseTests {
@Test
fun usingAfterDisposedThrows() {
val serviceLocator = ServiceLocator.getInstance(env = Env.Prod) as ProdServiceLocator
val service: FirebaseGameService =
serviceLocator.getGameServiceForGame("1234", start = false)
val service: FirebaseGameService = serviceLocator.getGameServiceForGame("1234", start = false)
service.dispose()
assertTrue(service.isDisposed)
val throwingActions: List<suspend (service: FirebaseGameService) -> Unit> =
listOf(
{ it.refreshGame() },
{ it.addRound() },
{ it.playHand(Hand.PAPER) },
{ it.currentRound },
{ it.currentGame },
{ it.startListening() },
{ it.stopListening() },
)
val throwingActions: List<suspend (service: FirebaseGameService) -> Unit> = listOf(
{ it.refreshGame() },
{ it.addRound() },
{ it.playHand(Hand.PAPER) },
{ it.currentRound },
{ it.currentGame },
{ it.startListening() },
{ it.stopListening() },
)

for (action in throwingActions) {
assertThrows(GameServiceException::class.java) {
Expand All @@ -162,9 +300,8 @@ class FirebaseTests {
}

@Test
fun firebaseReferences() {
val firebase =
(ServiceLocator.getInstance(env = Env.Prod) as ProdServiceLocator).firebaseReferences
fun testFirebaseReferences() {
val firebase = (ServiceLocator.getInstance(env = Env.Prod) as ProdServiceLocator).firebaseReferences
assertEquals("games", firebase.gamesCollection.path)

assertEquals("/profile_pictures", firebase.profilePicturesFolder.path)
Expand Down
Loading