Add user service tests
This commit is contained in:
parent
fc7fa6b5f7
commit
44859b1ecd
27
api/pom.xml
27
api/pom.xml
@ -161,6 +161,24 @@
|
|||||||
<version>1.0.2</version>
|
<version>1.0.2</version>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>io.ktor</groupId>
|
||||||
|
<artifactId>ktor-server-tests</artifactId>
|
||||||
|
<version>${ktor_version}</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.testcontainers</groupId>
|
||||||
|
<artifactId>mariadb</artifactId>
|
||||||
|
<version>1.14.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.amshove.kluent</groupId>
|
||||||
|
<artifactId>kluent</artifactId>
|
||||||
|
<version>1.61</version>
|
||||||
|
<scope>test</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
<build>
|
<build>
|
||||||
<sourceDirectory>${project.basedir}/src</sourceDirectory>
|
<sourceDirectory>${project.basedir}/src</sourceDirectory>
|
||||||
@ -174,12 +192,7 @@
|
|||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
<artifactId>maven-surefire-plugin</artifactId>
|
<artifactId>maven-surefire-plugin</artifactId>
|
||||||
<configuration>
|
<version>3.0.0-M4</version>
|
||||||
<includes>
|
|
||||||
<include>Test*</include>
|
|
||||||
<include>*Test</include>
|
|
||||||
</includes>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<artifactId>maven-compiler-plugin</artifactId>
|
<artifactId>maven-compiler-plugin</artifactId>
|
||||||
@ -210,7 +223,7 @@
|
|||||||
<configuration>
|
<configuration>
|
||||||
<experimentalCoroutines>enable</experimentalCoroutines>
|
<experimentalCoroutines>enable</experimentalCoroutines>
|
||||||
<sourceDirs>
|
<sourceDirs>
|
||||||
<sourceDir>${project.basedir}/src/test</sourceDir>
|
<sourceDir>${project.basedir}/test</sourceDir>
|
||||||
</sourceDirs>
|
</sourceDirs>
|
||||||
</configuration>
|
</configuration>
|
||||||
</execution>
|
</execution>
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
-- ON DELETE -> CASCADE
|
-- ON DELETE -> CASCADE
|
||||||
|
|
||||||
ALTER TABLE `Notes`
|
ALTER TABLE `Notes`
|
||||||
DROP CONSTRAINT `Notes_ibfk_1`;
|
DROP CONSTRAINT IF EXISTS `Notes_ibfk_1`;
|
||||||
|
|
||||||
ALTER TABLE `Notes`
|
ALTER TABLE `Notes`
|
||||||
ADD FOREIGN KEY (`user_id`) REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
|
ADD FOREIGN KEY (`user_id`) REFERENCES `Users` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
|
||||||
|
|
||||||
ALTER TABLE `Chapters`
|
ALTER TABLE `Chapters`
|
||||||
DROP CONSTRAINT `Chapters_ibfk_1`;
|
DROP CONSTRAINT IF EXISTS `Chapters_ibfk_1`;
|
||||||
|
|
||||||
ALTER TABLE `Chapters`
|
ALTER TABLE `Chapters`
|
||||||
ADD FOREIGN KEY (`note_id`) REFERENCES `Notes` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
|
ADD FOREIGN KEY (`note_id`) REFERENCES `Notes` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
|
||||||
|
|
||||||
ALTER TABLE `Tags`
|
ALTER TABLE `Tags`
|
||||||
DROP CONSTRAINT `Tags_ibfk_1`;
|
DROP CONSTRAINT IF EXISTS `Tags_ibfk_1`;
|
||||||
|
|
||||||
ALTER TABLE `Tags`
|
ALTER TABLE `Tags`
|
||||||
ADD FOREIGN KEY (`note_id`) REFERENCES `Notes` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
|
ADD FOREIGN KEY (`note_id`) REFERENCES `Notes` (`id`) ON DELETE CASCADE ON UPDATE RESTRICT;
|
||||||
|
|||||||
@ -12,4 +12,6 @@
|
|||||||
<logger name="org.eclipse.jetty" level="INFO"/>
|
<logger name="org.eclipse.jetty" level="INFO"/>
|
||||||
<logger name="io.netty" level="INFO"/>
|
<logger name="io.netty" level="INFO"/>
|
||||||
<logger name="org.flywaydb.core" level="INFO"/>
|
<logger name="org.flywaydb.core" level="INFO"/>
|
||||||
|
<logger name="org.testcontainers" level="INFO"/>
|
||||||
|
<logger name="com.github.dockerjava" level="INFO"/>
|
||||||
</configuration>
|
</configuration>
|
||||||
|
|||||||
@ -2,7 +2,6 @@ package be.vandewalleh.routing
|
|||||||
|
|
||||||
import be.vandewalleh.extensions.respondStatus
|
import be.vandewalleh.extensions.respondStatus
|
||||||
import be.vandewalleh.extensions.userId
|
import be.vandewalleh.extensions.userId
|
||||||
import be.vandewalleh.services.UserDto
|
|
||||||
import be.vandewalleh.services.UserService
|
import be.vandewalleh.services.UserService
|
||||||
import io.ktor.application.*
|
import io.ktor.application.*
|
||||||
import io.ktor.auth.*
|
import io.ktor.auth.*
|
||||||
@ -26,9 +25,7 @@ fun Routing.user(kodein: Kodein) {
|
|||||||
|
|
||||||
val hashedPassword = BCrypt.hashpw(user.password, BCrypt.gensalt())
|
val hashedPassword = BCrypt.hashpw(user.password, BCrypt.gensalt())
|
||||||
|
|
||||||
userService.createUser(
|
userService.createUser(user.username, user.email, hashedPassword)
|
||||||
UserDto(user.username, user.email, hashedPassword)
|
|
||||||
)
|
|
||||||
|
|
||||||
call.respondStatus(HttpStatusCode.Created)
|
call.respondStatus(HttpStatusCode.Created)
|
||||||
}
|
}
|
||||||
@ -42,10 +39,7 @@ fun Routing.user(kodein: Kodein) {
|
|||||||
|
|
||||||
val hashedPassword = BCrypt.hashpw(user.password, BCrypt.gensalt())
|
val hashedPassword = BCrypt.hashpw(user.password, BCrypt.gensalt())
|
||||||
|
|
||||||
userService.updateUser(
|
userService.updateUser(call.userId(), user.username, user.email, hashedPassword)
|
||||||
call.userId(),
|
|
||||||
UserDto(user.username, user.email, hashedPassword)
|
|
||||||
)
|
|
||||||
|
|
||||||
call.respondStatus(HttpStatusCode.OK)
|
call.respondStatus(HttpStatusCode.OK)
|
||||||
}
|
}
|
||||||
@ -57,5 +51,6 @@ fun Routing.user(kodein: Kodein) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
private data class UserDto(val username: String, val email: String, val password: String)
|
||||||
|
|||||||
@ -8,6 +8,7 @@ import me.liuwj.ktorm.entity.*
|
|||||||
import org.kodein.di.Kodein
|
import org.kodein.di.Kodein
|
||||||
import org.kodein.di.KodeinAware
|
import org.kodein.di.KodeinAware
|
||||||
import org.kodein.di.generic.instance
|
import org.kodein.di.generic.instance
|
||||||
|
import java.sql.SQLIntegrityConstraintViolationException
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -28,19 +29,14 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* returns a user email and password from it's email if found or null
|
* returns a user email and password from it's username if found or null
|
||||||
*/
|
*/
|
||||||
fun getFromUsername(username: String): UserSchema? {
|
fun getFromUsername(username: String): User? {
|
||||||
return db.from(Users)
|
return db.from(Users)
|
||||||
.select(Users.email, Users.password, Users.id)
|
.select(Users.email, Users.password, Users.id)
|
||||||
.where { Users.username eq username }
|
.where { Users.username eq username }
|
||||||
.map { row ->
|
.map { row ->
|
||||||
UserSchema(
|
Users.createEntity(row)
|
||||||
row[Users.id]!!,
|
|
||||||
username,
|
|
||||||
row[Users.email]!!,
|
|
||||||
row[Users.password]!!
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
}
|
}
|
||||||
@ -59,11 +55,11 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
|||||||
.firstOrNull() != null
|
.firstOrNull() != null
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getUserInfo(id: Int): UserInfoDto? {
|
fun getUserInfo(id: Int): User? {
|
||||||
return db.from(Users)
|
return db.from(Users)
|
||||||
.select(Users.email, Users.username)
|
.select(Users.email, Users.username)
|
||||||
.where { Users.id eq id }
|
.where { Users.id eq id }
|
||||||
.map { UserInfoDto(it[Users.username]!!, it[Users.email]!!) }
|
.map { Users.createEntity(it) }
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,25 +67,30 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
|||||||
* create a new user
|
* create a new user
|
||||||
* password should already be hashed
|
* password should already be hashed
|
||||||
*/
|
*/
|
||||||
fun createUser(user: UserDto) {
|
fun createUser(username: String, email: String, hashedPassword: String): User? {
|
||||||
db.useTransaction {
|
try {
|
||||||
val newUser = User {
|
db.useTransaction {
|
||||||
this.username = user.username
|
val newUser = User {
|
||||||
this.email = user.email
|
this.username = username
|
||||||
this.password = user.password
|
this.email = email
|
||||||
this.createdAt = LocalDateTime.now()
|
this.password = hashedPassword
|
||||||
}
|
this.createdAt = LocalDateTime.now()
|
||||||
|
}
|
||||||
|
|
||||||
db.sequenceOf(Users).add(newUser)
|
db.sequenceOf(Users).add(newUser)
|
||||||
|
return newUser
|
||||||
|
}
|
||||||
|
} catch (e: SQLIntegrityConstraintViolationException) {
|
||||||
|
return null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun updateUser(userId: Int, user: UserDto) {
|
fun updateUser(userId: Int, username: String, email: String, hashedPassword: String) {
|
||||||
db.useTransaction {
|
db.useTransaction {
|
||||||
db.update(Users) {
|
db.update(Users) {
|
||||||
it.username to user.username
|
it.username to username
|
||||||
it.email to user.email
|
it.email to email
|
||||||
it.password to user.password
|
it.password to hashedPassword
|
||||||
where {
|
where {
|
||||||
it.id eq userId
|
it.id eq userId
|
||||||
}
|
}
|
||||||
@ -104,6 +105,3 @@ class UserService(override val kodein: Kodein) : KodeinAware {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
data class UserSchema(val id: Int, val username: String, val email: String, val password: String)
|
|
||||||
data class UserDto(val username: String, val email: String, val password: String)
|
|
||||||
data class UserInfoDto(val username: String, val email: String)
|
|
||||||
|
|||||||
@ -1,37 +0,0 @@
|
|||||||
import be.vandewalleh.services.ChapterDTO
|
|
||||||
import be.vandewalleh.services.FullNoteCreateDTO
|
|
||||||
import be.vandewalleh.services.NotesService
|
|
||||||
import com.github.javafaker.Faker
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.kodein.di.generic.instance
|
|
||||||
|
|
||||||
class FakeDataTest {
|
|
||||||
val notesService by kodein.instance<NotesService>()
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun addNotes() {
|
|
||||||
val faker = Faker()
|
|
||||||
val title = faker.hobbit().quote()
|
|
||||||
|
|
||||||
val tags = listOf(
|
|
||||||
faker.beer().name(),
|
|
||||||
faker.beer().yeast()
|
|
||||||
)
|
|
||||||
|
|
||||||
val chapters = listOf(
|
|
||||||
ChapterDTO(
|
|
||||||
faker.animal().name(),
|
|
||||||
faker.lorem().paragraph()
|
|
||||||
),
|
|
||||||
ChapterDTO(
|
|
||||||
faker.animal().name(),
|
|
||||||
faker.lorem().paragraph()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
val note = FullNoteCreateDTO(title, tags, chapters)
|
|
||||||
|
|
||||||
notesService.createNote(1, note)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@ -1,50 +0,0 @@
|
|||||||
import be.vandewalleh.services.NotesService
|
|
||||||
import be.vandewalleh.services.UserService
|
|
||||||
import com.hekeki.huckleberry.Benchmark
|
|
||||||
import com.hekeki.huckleberry.BenchmarkRunner
|
|
||||||
import com.hekeki.huckleberry.BenchmarkTest
|
|
||||||
import com.hekeki.huckleberry.TimeUnit
|
|
||||||
import com.zaxxer.hikari.HikariConfig
|
|
||||||
import com.zaxxer.hikari.HikariDataSource
|
|
||||||
import me.liuwj.ktorm.database.*
|
|
||||||
import org.junit.jupiter.api.Assertions.*
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import org.kodein.di.Kodein
|
|
||||||
import org.kodein.di.generic.bind
|
|
||||||
import org.kodein.di.generic.instance
|
|
||||||
import org.kodein.di.generic.singleton
|
|
||||||
|
|
||||||
|
|
||||||
val hikariConfig = HikariConfig().apply {
|
|
||||||
jdbcUrl = "jdbc:mariadb://localhost:3306/notes"
|
|
||||||
username = "notes"
|
|
||||||
password = "notes"
|
|
||||||
}
|
|
||||||
|
|
||||||
val dataSource = HikariDataSource(hikariConfig)
|
|
||||||
|
|
||||||
val db = Database.Companion.connect(dataSource)
|
|
||||||
|
|
||||||
val kodein = Kodein {
|
|
||||||
bind<Database>() with singleton { db }
|
|
||||||
bind<UserService>() with singleton { UserService(this.kodein) }
|
|
||||||
bind<NotesService>() with singleton { NotesService(this.kodein) }
|
|
||||||
}
|
|
||||||
|
|
||||||
val notesService by kodein.instance<NotesService>()
|
|
||||||
|
|
||||||
@Benchmark(threads = 1, iterations = 30, warmup = true, warmupIterations = 1000, timeUnit = TimeUnit.MILLIS)
|
|
||||||
class RetrieveNotesBenchmarkTest : BenchmarkTest {
|
|
||||||
|
|
||||||
override fun execute() {
|
|
||||||
notesService.getNotes(15)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun compute() {
|
|
||||||
val benchmarkResult = BenchmarkRunner(RetrieveNotesBenchmarkTest::class.java).run()
|
|
||||||
assertTrue(benchmarkResult.median(2, TimeUnit.MILLIS))
|
|
||||||
assertTrue(benchmarkResult.maxTime(4, TimeUnit.MILLIS))
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
88
api/test/services/UserServiceTest.kt
Normal file
88
api/test/services/UserServiceTest.kt
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import be.vandewalleh.migrations.Migration
|
||||||
|
import be.vandewalleh.services.NotesService
|
||||||
|
import be.vandewalleh.services.UserService
|
||||||
|
import com.zaxxer.hikari.HikariConfig
|
||||||
|
import com.zaxxer.hikari.HikariDataSource
|
||||||
|
import me.liuwj.ktorm.database.*
|
||||||
|
import org.amshove.kluent.*
|
||||||
|
import org.junit.jupiter.api.*
|
||||||
|
import org.kodein.di.Kodein
|
||||||
|
import org.kodein.di.generic.bind
|
||||||
|
import org.kodein.di.generic.instance
|
||||||
|
import org.kodein.di.generic.singleton
|
||||||
|
import org.testcontainers.containers.MariaDBContainer
|
||||||
|
import javax.sql.DataSource
|
||||||
|
|
||||||
|
|
||||||
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
@TestMethodOrder(MethodOrderer.OrderAnnotation::class)
|
||||||
|
class UserServiceTest {
|
||||||
|
|
||||||
|
class KMariadbContainer : MariaDBContainer<KMariadbContainer>()
|
||||||
|
|
||||||
|
private val mariadb = KMariadbContainer().apply {
|
||||||
|
this.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val hikariConfig = HikariConfig().apply {
|
||||||
|
jdbcUrl = mariadb.jdbcUrl
|
||||||
|
username = mariadb.username
|
||||||
|
password = mariadb.password
|
||||||
|
}
|
||||||
|
|
||||||
|
private val dataSource = HikariDataSource(hikariConfig)
|
||||||
|
|
||||||
|
private val db = Database.Companion.connect(dataSource)
|
||||||
|
|
||||||
|
private val kodein = Kodein {
|
||||||
|
bind<DataSource>() with singleton { dataSource }
|
||||||
|
bind<Database>() with singleton { db }
|
||||||
|
bind<Migration>() with singleton { Migration(this.kodein) }
|
||||||
|
bind<UserService>() with singleton { UserService(this.kodein) }
|
||||||
|
bind<NotesService>() with singleton { NotesService(this.kodein) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private val migration by kodein.instance<Migration>()
|
||||||
|
|
||||||
|
init {
|
||||||
|
migration.migrate()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val userService by kodein.instance<UserService>()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(1)
|
||||||
|
fun `test create user`() {
|
||||||
|
val username = "hubert"
|
||||||
|
val email = "a@a"
|
||||||
|
val password = "password"
|
||||||
|
println(userService.createUser(username, email, password))
|
||||||
|
|
||||||
|
val id = userService.getUserId(email)
|
||||||
|
id `should not be` null
|
||||||
|
|
||||||
|
userService.getUserInfo(id!!)!!.let {
|
||||||
|
it.username `should be equal to` username
|
||||||
|
it.email `should be equal to` email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(2)
|
||||||
|
fun `test create same user`() {
|
||||||
|
userService.createUser(username = "hubert", hashedPassword = "password", email = "a@a") `should be` null
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Order(3)
|
||||||
|
fun `test delete user`() {
|
||||||
|
val email = "a@a"
|
||||||
|
val id = userService.getUserId(email)!!
|
||||||
|
userService.deleteUser(id)
|
||||||
|
|
||||||
|
userService.getUserId(email) `should be` null
|
||||||
|
userService.getUserInfo(id) `should be` null
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user