User service is now non blocking
This commit is contained in:
parent
ebd897093c
commit
6688b35a9b
@ -6,3 +6,8 @@ import kotlinx.coroutines.*
|
||||
fun <T> ioAsync(block: suspend CoroutineScope.() -> T): Deferred<T> {
|
||||
return CoroutineScope(Dispatchers.IO).async(block = block)
|
||||
}
|
||||
|
||||
suspend inline fun <T> launchIo(crossinline block: () -> T): T =
|
||||
withContext(Dispatchers.IO) {
|
||||
block()
|
||||
}
|
||||
|
||||
@ -1,7 +1,10 @@
|
||||
package be.vandewalleh.services
|
||||
|
||||
import be.vandewalleh.entities.User
|
||||
import be.vandewalleh.extensions.ioAsync
|
||||
import be.vandewalleh.extensions.launchIo
|
||||
import be.vandewalleh.tables.Users
|
||||
import kotlinx.coroutines.Deferred
|
||||
import me.liuwj.ktorm.database.*
|
||||
import me.liuwj.ktorm.dsl.*
|
||||
import me.liuwj.ktorm.entity.*
|
||||
@ -20,8 +23,8 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
||||
/**
|
||||
* returns a user ID if present or null
|
||||
*/
|
||||
fun getUserId(userEmail: String): Int? {
|
||||
return db.from(Users)
|
||||
suspend fun getUserId(userEmail: String): Int? = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.id)
|
||||
.where { Users.email eq userEmail }
|
||||
.map { it[Users.id] }
|
||||
@ -31,8 +34,8 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
||||
/**
|
||||
* returns a user email and password from it's username if found or null
|
||||
*/
|
||||
fun getFromUsername(username: String): User? {
|
||||
return db.from(Users)
|
||||
suspend fun getFromUsername(username: String): User? = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.email, Users.password, Users.id)
|
||||
.where { Users.username eq username }
|
||||
.map { row ->
|
||||
@ -41,22 +44,22 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
||||
.firstOrNull()
|
||||
}
|
||||
|
||||
fun userExists(username: String, email: String): Boolean {
|
||||
return db.from(Users)
|
||||
suspend fun userExists(username: String, email: String): Boolean = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.id)
|
||||
.where { (Users.username eq username) or (Users.email eq email) }
|
||||
.firstOrNull() != null
|
||||
}
|
||||
|
||||
fun userExists(userId: Int): Boolean {
|
||||
return db.from(Users)
|
||||
suspend fun userExists(userId: Int): Boolean = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.id)
|
||||
.where { Users.id eq userId }
|
||||
.firstOrNull() != null
|
||||
}
|
||||
|
||||
fun getUserInfo(id: Int): User? {
|
||||
return db.from(Users)
|
||||
suspend fun getUserInfo(id: Int): User? = launchIo {
|
||||
db.from(Users)
|
||||
.select(Users.email, Users.username)
|
||||
.where { Users.id eq id }
|
||||
.map { Users.createEntity(it) }
|
||||
@ -67,25 +70,27 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
||||
* create a new user
|
||||
* password should already be hashed
|
||||
*/
|
||||
fun createUser(username: String, email: String, hashedPassword: String): User? {
|
||||
try {
|
||||
db.useTransaction {
|
||||
suspend fun createUser(username: String, email: String, hashedPassword: String): User? {
|
||||
val newUser = User {
|
||||
this.username = username
|
||||
this.email = email
|
||||
this.password = hashedPassword
|
||||
this.createdAt = LocalDateTime.now()
|
||||
password = hashedPassword
|
||||
createdAt = LocalDateTime.now()
|
||||
}
|
||||
|
||||
return try {
|
||||
launchIo {
|
||||
db.useTransaction {
|
||||
db.sequenceOf(Users).add(newUser)
|
||||
return newUser
|
||||
newUser
|
||||
}
|
||||
}
|
||||
} catch (e: SQLIntegrityConstraintViolationException) {
|
||||
return null
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
fun updateUser(userId: Int, username: String, email: String, hashedPassword: String) {
|
||||
suspend fun updateUser(userId: Int, username: String, email: String, hashedPassword: String): Unit = launchIo {
|
||||
db.useTransaction {
|
||||
db.update(Users) {
|
||||
it.username to username
|
||||
@ -98,14 +103,17 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
||||
}
|
||||
}
|
||||
|
||||
fun deleteUser(userId: Int): Boolean {
|
||||
suspend fun deleteUser(userId: Int): Boolean = launchIo {
|
||||
db.useTransaction {
|
||||
return when (db.delete(Users) { it.id eq userId }) {
|
||||
db.delete(Users) { it.id eq userId }
|
||||
}
|
||||
}.let {
|
||||
when (it) {
|
||||
1 -> true
|
||||
0 -> false
|
||||
else -> error("??")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -10,7 +10,8 @@ import com.auth0.jwt.JWT
|
||||
import com.auth0.jwt.algorithms.Algorithm
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.testing.*
|
||||
import io.mockk.every
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.mockk
|
||||
import io.mockk.verify
|
||||
import org.amshove.kluent.*
|
||||
@ -36,9 +37,9 @@ class AuthControllerKtTest {
|
||||
}
|
||||
user["id"] = 1
|
||||
|
||||
every { userService.getFromUsername("existing") } returns user
|
||||
every { userService.userExists(1) } returns true
|
||||
every { userService.getUserInfo(1) } returns User {
|
||||
coEvery { userService.getFromUsername("existing") } returns user
|
||||
coEvery { userService.userExists(1) } returns true
|
||||
coEvery { userService.getUserInfo(1) } returns User {
|
||||
username = "existing"
|
||||
email = "existing@mail.com"
|
||||
}
|
||||
@ -48,12 +49,12 @@ class AuthControllerKtTest {
|
||||
username = "wrong"
|
||||
}
|
||||
user["id"] = 2
|
||||
every { userService.getFromUsername("wrong") } returns user2
|
||||
coEvery { userService.getFromUsername("wrong") } returns user2
|
||||
|
||||
every { userService.getFromUsername("notExisting") } returns null
|
||||
coEvery { userService.getFromUsername("notExisting") } returns null
|
||||
|
||||
every { userService.userExists(3) } returns false
|
||||
every { userService.getUserInfo(3) } returns null
|
||||
coEvery { userService.userExists(3) } returns false
|
||||
coEvery { userService.getUserInfo(3) } returns null
|
||||
}
|
||||
|
||||
|
||||
@ -78,7 +79,7 @@ class AuthControllerKtTest {
|
||||
}
|
||||
}
|
||||
|
||||
verify { userService.getFromUsername("existing") }
|
||||
coVerify { userService.getFromUsername("existing") }
|
||||
|
||||
res.status() `should be equal to` HttpStatusCode.OK
|
||||
val jsonObject = JSONObject(res.content)
|
||||
@ -106,7 +107,7 @@ class AuthControllerKtTest {
|
||||
}
|
||||
}
|
||||
|
||||
verify { userService.getFromUsername("wrong") }
|
||||
coVerify { userService.getFromUsername("wrong") }
|
||||
|
||||
res.status() `should be equal to` HttpStatusCode.Unauthorized
|
||||
res.content `should strictly be equal to json` """{msg: "Unauthorized"}"""
|
||||
@ -121,7 +122,7 @@ class AuthControllerKtTest {
|
||||
}
|
||||
}
|
||||
|
||||
verify { userService.getFromUsername("notExisting") }
|
||||
coVerify { userService.getFromUsername("notExisting") }
|
||||
|
||||
res.status() `should be equal to` HttpStatusCode.Unauthorized
|
||||
res.content `should strictly be equal to json` """{msg: "Unauthorized"}"""
|
||||
@ -154,7 +155,7 @@ class AuthControllerKtTest {
|
||||
val jsonObject = JSONObject(res.content)
|
||||
jsonObject.keyList() `should be equal to` listOf("token", "refreshToken")
|
||||
|
||||
verify { userService.userExists(1) }
|
||||
coVerify { userService.userExists(1) }
|
||||
res.status() `should be equal to` HttpStatusCode.OK
|
||||
}
|
||||
|
||||
@ -169,7 +170,7 @@ class AuthControllerKtTest {
|
||||
}
|
||||
}
|
||||
|
||||
verify { userService.userExists(3) }
|
||||
coVerify { userService.userExists(3) }
|
||||
res.status() `should be equal to` HttpStatusCode.Unauthorized
|
||||
res.content `should strictly be equal to json` """{msg: "Unauthorized"}"""
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import be.vandewalleh.module
|
||||
import be.vandewalleh.services.UserService
|
||||
import io.ktor.http.*
|
||||
import io.ktor.server.testing.*
|
||||
import io.mockk.every
|
||||
import io.mockk.coEvery
|
||||
import io.mockk.mockk
|
||||
import org.amshove.kluent.*
|
||||
import org.junit.jupiter.api.*
|
||||
@ -24,31 +24,31 @@ class UserControllerKtTest {
|
||||
|
||||
init {
|
||||
// new user
|
||||
every { userService.userExists("new", "new@test.com") } returns false
|
||||
every { userService.createUser("new", "new@test.com", any()) } returns User {
|
||||
coEvery { userService.userExists("new", "new@test.com") } returns false
|
||||
coEvery { userService.createUser("new", "new@test.com", any()) } returns User {
|
||||
this.createdAt = LocalDateTime.now()
|
||||
this.username = "new"
|
||||
this.email = "new@test.com"
|
||||
}
|
||||
|
||||
// existing user
|
||||
every { userService.userExists("existing", "existing@test.com") } returns true
|
||||
every { userService.createUser("existing", "existing@test.com", any()) } returns null
|
||||
every { userService.getUserId("existing@test.com") } returns 1
|
||||
every { userService.deleteUser(1) } returns true andThen false
|
||||
coEvery { userService.userExists("existing", "existing@test.com") } returns true
|
||||
coEvery { userService.createUser("existing", "existing@test.com", any()) } returns null
|
||||
coEvery { userService.getUserId("existing@test.com") } returns 1
|
||||
coEvery { userService.deleteUser(1) } returns true andThen false
|
||||
|
||||
// modified user
|
||||
every { userService.userExists("modified", "modified@test.com") } returns true
|
||||
every {
|
||||
coEvery { userService.userExists("modified", "modified@test.com") } returns true
|
||||
coEvery {
|
||||
userService.userExists(
|
||||
and(not("modified"), not("existing")),
|
||||
and(not("modified@test.com"), not("existing@test.com"))
|
||||
)
|
||||
} returns false
|
||||
every { userService.userExists(1) } returns true
|
||||
every { userService.createUser("modified", "modified@test.com", any()) } returns null
|
||||
every { userService.getUserId("modified@test.com") } returns 1
|
||||
every { userService.updateUser(1, "ThisIsMyNewName", "ThisIsMyNewName@mail.com", any()) } returns Unit
|
||||
coEvery { userService.userExists(1) } returns true
|
||||
coEvery { userService.createUser("modified", "modified@test.com", any()) } returns null
|
||||
coEvery { userService.getUserId("modified@test.com") } returns 1
|
||||
coEvery { userService.updateUser(1, "ThisIsMyNewName", "ThisIsMyNewName@mail.com", any()) } returns Unit
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -3,6 +3,7 @@ package integration.services
|
||||
import be.vandewalleh.mainModule
|
||||
import be.vandewalleh.migrations.Migration
|
||||
import be.vandewalleh.services.UserService
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.amshove.kluent.*
|
||||
import org.junit.jupiter.api.*
|
||||
import org.kodein.di.Kodein
|
||||
@ -36,11 +37,12 @@ class UserServiceTest {
|
||||
@Test
|
||||
@Order(1)
|
||||
fun `test create user`() {
|
||||
runBlocking {
|
||||
val username = "hubert"
|
||||
val email = "a@a"
|
||||
val password = "password"
|
||||
println(userService.createUser(username, email, password))
|
||||
|
||||
userService.createUser(username, email, password)
|
||||
val id = userService.getUserId(email)
|
||||
id `should not be` null
|
||||
|
||||
@ -49,16 +51,20 @@ class UserServiceTest {
|
||||
it.email `should be equal to` email
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(2)
|
||||
fun `test create same user`() {
|
||||
runBlocking {
|
||||
userService.createUser(username = "hubert", hashedPassword = "password", email = "a@a") `should be` null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(3)
|
||||
fun `test delete user`() {
|
||||
runBlocking {
|
||||
val email = "a@a"
|
||||
val id = userService.getUserId(email)!!
|
||||
userService.deleteUser(id)
|
||||
@ -67,3 +73,5 @@ class UserServiceTest {
|
||||
userService.getUserInfo(id) `should be` null
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user