From 7ab20b3dac6d9fccf4cd77da73a5f2ac222a8b3c Mon Sep 17 00:00:00 2001 From: Sebastian Date: Fri, 29 Sep 2023 23:54:08 -0700 Subject: [PATCH] Improve repository tests --- .../net/wiringbits/core/RepositorySpec.scala | 2 + .../BackgroundJobsRepositorySpec.scala | 88 +++------ .../repositories/UserLogsRepositorySpec.scala | 60 ++---- .../UserTokensRepositorySpec.scala | 103 ++--------- .../repositories/UsersRepositorySpec.scala | 173 ++++-------------- .../test/scala/utils/RepositoryUtils.scala | 94 ++++++++++ 6 files changed, 187 insertions(+), 333 deletions(-) create mode 100644 server/src/test/scala/utils/RepositoryUtils.scala diff --git a/server/src/test/scala/net/wiringbits/core/RepositorySpec.scala b/server/src/test/scala/net/wiringbits/core/RepositorySpec.scala index 64ad4eff..88a5ee79 100644 --- a/server/src/test/scala/net/wiringbits/core/RepositorySpec.scala +++ b/server/src/test/scala/net/wiringbits/core/RepositorySpec.scala @@ -7,10 +7,12 @@ import org.scalatest.wordspec.AnyWordSpec import utils.Executors import java.time.Clock +import scala.concurrent.ExecutionContext import scala.concurrent.duration.DurationInt trait RepositorySpec extends AnyWordSpec with PostgresSpec { implicit val patienceConfig: PatienceConfig = PatienceConfig(30.seconds, 1.second) + implicit val executionContext: ExecutionContext = Executors.globalEC def withRepositories[T](clock: Clock = Clock.systemUTC)(runTest: RepositoryComponents => T): T = withDatabase { db => val users = new UsersRepository(db, UserTokensConfig(1.hour, 1.hour, "secret"))(Executors.databaseEC, clock) diff --git a/server/src/test/scala/net/wiringbits/repositories/BackgroundJobsRepositorySpec.scala b/server/src/test/scala/net/wiringbits/repositories/BackgroundJobsRepositorySpec.scala index 9cdaada2..928e3e51 100644 --- a/server/src/test/scala/net/wiringbits/repositories/BackgroundJobsRepositorySpec.scala +++ b/server/src/test/scala/net/wiringbits/repositories/BackgroundJobsRepositorySpec.scala @@ -5,18 +5,19 @@ import akka.stream.scaladsl.* import net.wiringbits.common.models.Email import net.wiringbits.core.RepositorySpec import net.wiringbits.models.jobs.{BackgroundJobPayload, BackgroundJobStatus, BackgroundJobType} -import net.wiringbits.repositories.daos.BackgroundJobDAO +import net.wiringbits.repositories.daos.{BackgroundJobDAO, backgroundJobParser} import net.wiringbits.repositories.models.BackgroundJobData import org.scalatest.BeforeAndAfterAll import org.scalatest.OptionValues.* import org.scalatest.concurrent.ScalaFutures.* import org.scalatest.matchers.must.Matchers.* import play.api.libs.json.Json +import utils.RepositoryUtils import java.time.Instant import java.util.UUID -class BackgroundJobsRepositorySpec extends RepositorySpec with BeforeAndAfterAll { +class BackgroundJobsRepositorySpec extends RepositorySpec with BeforeAndAfterAll with RepositoryUtils { // required to test the streaming operations private implicit lazy val system: ActorSystem = ActorSystem("BackgroundJobsRepositorySpec") @@ -26,24 +27,10 @@ class BackgroundJobsRepositorySpec extends RepositorySpec with BeforeAndAfterAll super.afterAll() } - private val backgroundJobPayload = - BackgroundJobPayload.SendEmail(Email.trusted("sample@wiringbits.net"), subject = "Test message", body = "it works") "streamPendingJobs" should { - "work (simple case)" in withRepositories() { repositories => - val createRequest = BackgroundJobData.Create( - id = UUID.randomUUID(), - `type` = BackgroundJobType.SendEmail, - payload = backgroundJobPayload, - status = BackgroundJobStatus.Pending, - executeAt = Instant.now(), - createdAt = Instant.now(), - updatedAt = Instant.now() - ) - - repositories.database.withConnection { implicit conn => - BackgroundJobDAO.create(createRequest) - } + "work (simple case)" in withRepositories() { implicit repositories => + val createRequest = createBackgroundJobData() val result = repositories.backgroundJobs.streamPendingJobs.futureValue .runWith(Sink.seq) @@ -56,27 +43,16 @@ class BackgroundJobsRepositorySpec extends RepositorySpec with BeforeAndAfterAll item.payload must be(Json.toJson(createRequest.payload)) } - "only return pending jobs" in withRepositories() { repositories => - val createRequestBase = BackgroundJobData.Create( - id = UUID.randomUUID(), - `type` = BackgroundJobType.SendEmail, - payload = backgroundJobPayload, - status = BackgroundJobStatus.Pending, - executeAt = Instant.now(), - createdAt = Instant.now(), - updatedAt = Instant.now() - ) - + "only return pending jobs" in withRepositories() { implicit repositories => + val backgroundJobType = BackgroundJobType.SendEmail + val payload = backgroundJobPayload val limit = 6 for (i <- 1 to limit) { - repositories.database.withConnection { implicit conn => - BackgroundJobDAO.create( - createRequestBase.copy( - id = UUID.randomUUID(), - status = if ((i % 2) == 0) BackgroundJobStatus.Success else BackgroundJobStatus.Pending - ) - ) - } + createBackgroundJobData( + backgroundJobType = backgroundJobType, + payload = payload, + status = if (i % 2) == 0 then BackgroundJobStatus.Success else BackgroundJobStatus.Pending + ) } val response = repositories.backgroundJobs.streamPendingJobs.futureValue .runWith(Sink.seq) @@ -84,8 +60,8 @@ class BackgroundJobsRepositorySpec extends RepositorySpec with BeforeAndAfterAll response.length must be(limit / 2) response.foreach { x => x.status must be(BackgroundJobStatus.Pending) - x.`type` must be(createRequestBase.`type`) - x.payload must be(Json.toJson(createRequestBase.payload)) + x.`type` must be(backgroundJobType) + x.payload must be(Json.toJson(payload)) } } @@ -98,20 +74,9 @@ class BackgroundJobsRepositorySpec extends RepositorySpec with BeforeAndAfterAll } "setStatusToFailed" should { - "work" in withRepositories() { repositories => - val createRequest = BackgroundJobData.Create( - id = UUID.randomUUID(), - `type` = BackgroundJobType.SendEmail, - payload = backgroundJobPayload, - status = BackgroundJobStatus.Pending, - executeAt = Instant.now(), - createdAt = Instant.now(), - updatedAt = Instant.now() - ) - - repositories.database.withConnection { implicit conn => - BackgroundJobDAO.create(createRequest) - } + "work" in withRepositories() { implicit repositories => + val createRequest = createBackgroundJobData() + val failReason = "test" repositories.backgroundJobs .setStatusToFailed(createRequest.id, executeAt = Instant.now(), failReason = failReason) @@ -137,20 +102,9 @@ class BackgroundJobsRepositorySpec extends RepositorySpec with BeforeAndAfterAll } "setStatusToSuccess" should { - "work" in withRepositories() { repositories => - val createRequest = BackgroundJobData.Create( - id = UUID.randomUUID(), - `type` = BackgroundJobType.SendEmail, - payload = backgroundJobPayload, - status = BackgroundJobStatus.Pending, - executeAt = Instant.now(), - createdAt = Instant.now(), - updatedAt = Instant.now() - ) - - repositories.database.withConnection { implicit conn => - BackgroundJobDAO.create(createRequest) - } + "work" in withRepositories() { implicit repositories => + val createRequest = createBackgroundJobData() + repositories.backgroundJobs.setStatusToSuccess(createRequest.id).futureValue val result = repositories.backgroundJobs.streamPendingJobs.futureValue diff --git a/server/src/test/scala/net/wiringbits/repositories/UserLogsRepositorySpec.scala b/server/src/test/scala/net/wiringbits/repositories/UserLogsRepositorySpec.scala index a996b9be..801879c6 100644 --- a/server/src/test/scala/net/wiringbits/repositories/UserLogsRepositorySpec.scala +++ b/server/src/test/scala/net/wiringbits/repositories/UserLogsRepositorySpec.scala @@ -1,34 +1,23 @@ package net.wiringbits.repositories -import net.wiringbits.common.models.{Email, Name} import net.wiringbits.core.RepositorySpec -import net.wiringbits.repositories.models.{User, UserLog} import org.scalatest.concurrent.ScalaFutures.* import org.scalatest.matchers.must.Matchers.* +import utils.RepositoryUtils import java.util.UUID -class UserLogsRepositorySpec extends RepositorySpec { +class UserLogsRepositorySpec extends RepositorySpec with RepositoryUtils { "create" should { - "work" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "work" in withRepositories() { implicit repositories => + val request = createUser().futureValue - val logsRequest = UserLog.CreateUserLog(userLogId = UUID.randomUUID(), userId = request.id, message = "test") - repositories.userLogs.create(logsRequest).futureValue + createUserLog(request.id).futureValue } - "fail if the user doesn't exists" in withRepositories() { repositories => - val logsRequest = - UserLog.CreateUserLog(userLogId = UUID.randomUUID(), userId = UUID.randomUUID(), message = "test") + "fail if the user doesn't exists" in withRepositories() { implicit repositories => val ex = intercept[RuntimeException] { - repositories.userLogs.create(logsRequest).futureValue + createUserLog(UUID.randomUUID()).futureValue } ex.getCause.getMessage must startWith( s"""ERROR: insert or update on table "user_logs" violates foreign key constraint "user_logs_users_fk"""" @@ -37,22 +26,15 @@ class UserLogsRepositorySpec extends RepositorySpec { } "create(userId, message)" should { - "work" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "work" in withRepositories() { implicit repositories => + val request = createUser().futureValue - repositories.userLogs.create(request.id, "test").futureValue + createUserLog(request.id, "test").futureValue } - "fail if the user doesn't exists" in withRepositories() { repositories => + "fail if the user doesn't exists" in withRepositories() { implicit repositories => val ex = intercept[RuntimeException] { - repositories.userLogs.create(UUID.randomUUID(), "test").futureValue + createUserLog(UUID.randomUUID(), "test").futureValue } ex.getCause.getMessage must startWith( s"""ERROR: insert or update on table "user_logs" violates foreign key constraint "user_logs_users_fk"""" @@ -61,24 +43,18 @@ class UserLogsRepositorySpec extends RepositorySpec { } "logs" should { - "return every log" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "return every log" in withRepositories() { implicit repositories => + val request = createUser().futureValue val message = "test" - for (_ <- 1 to 3) { - repositories.userLogs.create(request.id, message).futureValue + val expected = 3 + (1 to expected).foreach { _ => + createUserLog(request.id, message).futureValue } val response = repositories.userLogs.logs(request.id).futureValue // Creating a user generates a user log. 3 + 1 - response.length must be(4) + response.length must be(expected + 1) } "return no results" in withRepositories() { repositories => diff --git a/server/src/test/scala/net/wiringbits/repositories/UserTokensRepositorySpec.scala b/server/src/test/scala/net/wiringbits/repositories/UserTokensRepositorySpec.scala index e82047bc..169b64ba 100644 --- a/server/src/test/scala/net/wiringbits/repositories/UserTokensRepositorySpec.scala +++ b/server/src/test/scala/net/wiringbits/repositories/UserTokensRepositorySpec.scala @@ -1,52 +1,24 @@ package net.wiringbits.repositories -import net.wiringbits.common.models.{Email, Name} import net.wiringbits.core.RepositorySpec -import net.wiringbits.repositories.models.{User, UserToken, UserTokenType} import org.scalatest.OptionValues.convertOptionToValuable import org.scalatest.concurrent.ScalaFutures.* import org.scalatest.matchers.must.Matchers.* +import utils.RepositoryUtils -import java.time.Instant -import java.time.temporal.ChronoUnit import java.util.UUID -class UserTokensRepositorySpec extends RepositorySpec { +class UserTokensRepositorySpec extends RepositorySpec with RepositoryUtils { "create" should { - "work" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue - - val tokenRequest = - UserToken.Create( - id = UUID.randomUUID(), - token = "test", - tokenType = UserTokenType.ResetPassword, - createdAt = Instant.now(), - expiresAt = Instant.now.plus(2, ChronoUnit.DAYS), - userId = request.id - ) - repositories.userTokens.create(tokenRequest).futureValue + "work" in withRepositories() { implicit repositories => + val request = createUser().futureValue + + createToken(request.id).futureValue } - "fail when the user doesn't exists" in withRepositories() { repositories => - val tokenRequest = - UserToken.Create( - id = UUID.randomUUID(), - token = "test", - tokenType = UserTokenType.ResetPassword, - createdAt = Instant.now(), - expiresAt = Instant.now.plus(2, ChronoUnit.DAYS), - userId = UUID.randomUUID() - ) + "fail when the user doesn't exists" in withRepositories() { implicit repositories => val ex = intercept[RuntimeException] { - repositories.userTokens.create(tokenRequest).futureValue + createToken(UUID.randomUUID()).futureValue } ex.getCause.getMessage must startWith( s"""ERROR: insert or update on table "user_tokens" violates foreign key constraint "user_tokens_user_id_fk"""" @@ -55,26 +27,10 @@ class UserTokensRepositorySpec extends RepositorySpec { } "find(userId)" should { - "return the user token" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue - - val tokenRequest = - UserToken.Create( - id = UUID.randomUUID(), - token = "test", - tokenType = UserTokenType.ResetPassword, - createdAt = Instant.now(), - expiresAt = Instant.now.plus(2, ChronoUnit.DAYS), - userId = request.id - ) - repositories.userTokens.create(tokenRequest).futureValue + "return the user token" in withRepositories() { implicit repositories => + val request = createUser().futureValue + + val tokenRequest = createToken(request.id).futureValue val maybe = repositories.userTokens.find(request.id).futureValue val response = maybe.headOption.value @@ -90,26 +46,10 @@ class UserTokensRepositorySpec extends RepositorySpec { } "find(userId, token)" should { - "return the user token" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue - - val tokenRequest = - UserToken.Create( - id = UUID.randomUUID(), - token = "test", - tokenType = UserTokenType.ResetPassword, - createdAt = Instant.now(), - expiresAt = Instant.now.plus(2, ChronoUnit.DAYS), - userId = request.id - ) - repositories.userTokens.create(tokenRequest).futureValue + "return the user token" in withRepositories() { implicit repositories => + val request = createUser().futureValue + + val tokenRequest = createToken(request.id).futureValue val response = repositories.userTokens.find(request.id, tokenRequest.token).futureValue response.isDefined must be(true) @@ -122,15 +62,8 @@ class UserTokensRepositorySpec extends RepositorySpec { } "delete" should { - "work" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "work" in withRepositories() { implicit repositories => + val request = createUser().futureValue val maybe = repositories.userTokens.find(request.id).futureValue val tokenId = maybe.headOption.value.id diff --git a/server/src/test/scala/net/wiringbits/repositories/UsersRepositorySpec.scala b/server/src/test/scala/net/wiringbits/repositories/UsersRepositorySpec.scala index 02ac0f5b..7f7842bc 100644 --- a/server/src/test/scala/net/wiringbits/repositories/UsersRepositorySpec.scala +++ b/server/src/test/scala/net/wiringbits/repositories/UsersRepositorySpec.scala @@ -10,10 +10,11 @@ import org.scalatest.BeforeAndAfterAll import org.scalatest.OptionValues.* import org.scalatest.concurrent.ScalaFutures.* import org.scalatest.matchers.must.Matchers.* +import utils.RepositoryUtils import java.util.UUID -class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { +class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll with RepositoryUtils { // required to test the streaming operations private implicit lazy val system: ActorSystem = ActorSystem("UserRepositorySpec") @@ -24,41 +25,19 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { } "create" should { - "work" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "work" in withRepositories() { implicit repositories => + createUser().futureValue } - "create a token for verifying the email" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "create a token for verifying the email" in withRepositories() { implicit repositories => + val request = createUser().futureValue val response = repositories.userTokens.find(request.id).futureValue response.nonEmpty must be(true) } - "fail when the id already exists" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - - repositories.users.create(request).futureValue + "fail when the id already exists" in withRepositories() { implicit repositories => + val request = createUser().futureValue val ex = intercept[RuntimeException] { repositories.users.create(request.copy(email = Email.trusted("email2@wiringbits.net"))).futureValue } @@ -68,16 +47,8 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { ) } - "fail when the email already exists" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - - repositories.users.create(request).futureValue + "fail when the email already exists" in withRepositories() { implicit repositories => + val request = createUser().futureValue val ex = intercept[RuntimeException] { repositories.users.create(request.copy(id = UUID.randomUUID())).futureValue } @@ -89,16 +60,10 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { } "all" should { - "return the existing users" in withRepositories() { repositories => - for (i <- 1 to 3) { - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted(s"test$i@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "return the existing users" in withRepositories() { implicit repositories => + val expected = 3 + for (i <- 1 to expected) { + createUser(email = Email.trusted(s"test$i@wiringbits.net")).futureValue } val response = repositories.users.all().futureValue @@ -112,15 +77,8 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { } "find(email)" should { - "return a user when the email exists" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "return a user when the email exists" in withRepositories() { implicit repositories => + val request = createUser().futureValue val response = repositories.users.find(request.email).futureValue response.value.email must be(request.email) @@ -128,15 +86,8 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { response.value.hashedPassword must be(request.hashedPassword) } - "return a user when the email exists (case insensitive match)" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "return a user when the email exists (case insensitive match)" in withRepositories() { implicit repositories => + val request = createUser().futureValue val email = Email.trusted(request.email.string.toUpperCase) val response = repositories.users.find(email).futureValue @@ -151,15 +102,8 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { } "find(id)" should { - "return a user when the id exists" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "return a user when the id exists" in withRepositories() { implicit repositories => + val request = createUser().futureValue val response = repositories.users.find(request.id).futureValue response.value.email must be(request.email) @@ -175,15 +119,8 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { } "update" should { - "update an existing user" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "update an existing user" in withRepositories() { implicit repositories => + val request = createUser().futureValue val newName = Name.trusted("Test") repositories.users.update(request.id, newName).futureValue @@ -206,15 +143,8 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { } "updatePassword" should { - "update the password for an existing user" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "update the password for an existing user" in withRepositories() { implicit repositories => + val request = createUser().futureValue val newPassword = "test" repositories.users.updatePassword(request.id, newPassword, EmailMessage.updatePassword(request.name)).futureValue @@ -223,15 +153,8 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { response.value.hashedPassword must be(newPassword) } - "produce a notification for the user" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "produce a notification for the user" in withRepositories() { implicit repositories => + val request = createUser().futureValue val newPassword = "test" repositories.users.updatePassword(request.id, newPassword, EmailMessage.updatePassword(request.name)).futureValue @@ -254,30 +177,16 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { } "verify" should { - "verify a user given a token" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "verify a user given a token" in withRepositories() { implicit repositories => + val request = createUser().futureValue repositories.users.verify(request.id, UUID.randomUUID(), EmailMessage.confirm(request.name)).futureValue val response = repositories.users.find(request.id).futureValue response.value.verifiedOn.isDefined must be(true) } - "produce a notification for the user" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "produce a notification for the user" in withRepositories() { implicit repositories => + val request = createUser().futureValue repositories.users.verify(request.id, UUID.randomUUID(), EmailMessage.confirm(request.name)).futureValue val response = repositories.backgroundJobs.streamPendingJobs.futureValue @@ -298,15 +207,8 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { } "resetPassword" should { - "update the password" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "update the password" in withRepositories() { implicit repositories => + val request = createUser().futureValue val newPassword = "test" repositories.users.resetPassword(request.id, newPassword, EmailMessage.resetPassword(request.name)).futureValue @@ -315,15 +217,8 @@ class UsersRepositorySpec extends RepositorySpec with BeforeAndAfterAll { response.value.hashedPassword must be(newPassword) } - "produce a notification for the user" in withRepositories() { repositories => - val request = User.CreateUser( - id = UUID.randomUUID(), - email = Email.trusted("hello@wiringbits.net"), - name = Name.trusted("Sample"), - hashedPassword = "password", - verifyEmailToken = "token" - ) - repositories.users.create(request).futureValue + "produce a notification for the user" in withRepositories() { implicit repositories => + val request = createUser().futureValue val newPassword = "test" repositories.users.resetPassword(request.id, newPassword, EmailMessage.resetPassword(request.name)).futureValue diff --git a/server/src/test/scala/utils/RepositoryUtils.scala b/server/src/test/scala/utils/RepositoryUtils.scala new file mode 100644 index 00000000..7bca4f1b --- /dev/null +++ b/server/src/test/scala/utils/RepositoryUtils.scala @@ -0,0 +1,94 @@ +package utils + +import net.wiringbits.common.models.{Email, Name} +import net.wiringbits.core.RepositoryComponents +import net.wiringbits.models.jobs.{BackgroundJobPayload, BackgroundJobStatus, BackgroundJobType} +import net.wiringbits.repositories.daos.BackgroundJobDAO +import net.wiringbits.repositories.models.{BackgroundJobData, User, UserLog, UserToken, UserTokenType} +import org.scalatest.concurrent.ScalaFutures.* + +import java.time.Instant +import java.time.temporal.ChronoUnit +import java.util.UUID +import scala.annotation.unused +import scala.concurrent.{ExecutionContext, Future} + +trait RepositoryUtils { + val backgroundJobPayload: BackgroundJobPayload.SendEmail = + BackgroundJobPayload.SendEmail(Email.trusted("sample@wiringbits.net"), subject = "Test message", body = "it works") + + def createBackgroundJobData( + id: UUID = UUID.randomUUID(), + backgroundJobType: BackgroundJobType = BackgroundJobType.SendEmail, + status: BackgroundJobStatus = BackgroundJobStatus.Pending, + payload: BackgroundJobPayload = backgroundJobPayload + )(using repositories: RepositoryComponents): BackgroundJobData.Create = { + val createRequest = BackgroundJobData.Create( + id = id, + `type` = backgroundJobType, + payload = payload, + status = status, + executeAt = Instant.now(), + createdAt = Instant.now(), + updatedAt = Instant.now() + ) + + repositories.database.withConnection { implicit conn => + BackgroundJobDAO.create(createRequest) + } + + createRequest + } + + def createUser( + email: Email = Email.trusted("hello@wiringbits.net") + )(using repository: RepositoryComponents)(using @unused ec: ExecutionContext): Future[User.CreateUser] = { + val createRequest = User.CreateUser( + id = UUID.randomUUID(), + email = email, + name = Name.trusted("Sample"), + hashedPassword = "password", + verifyEmailToken = "token" + ) + + for { + _ <- repository.users.create(createRequest) + } yield createRequest + } + + def createUserLog( + userId: UUID + )(using repository: RepositoryComponents)(using @unused ec: ExecutionContext): Future[UserLog.CreateUserLog] = { + val createRequest = + UserLog.CreateUserLog(userLogId = UUID.randomUUID(), userId = userId, message = "test") + + for { + _ <- repository.userLogs.create(createRequest) + } yield createRequest + } + + def createUserLog( + userId: UUID, + message: String + )(using repository: RepositoryComponents): Future[Unit] = { + repository.userLogs.create(userId, message) + } + + def createToken( + userId: UUID + )(using @unused ec: ExecutionContext, repository: RepositoryComponents): Future[UserToken.Create] = { + val tokenRequest = + UserToken.Create( + id = UUID.randomUUID(), + token = "test", + tokenType = UserTokenType.ResetPassword, + createdAt = Instant.now(), + expiresAt = Instant.now.plus(2, ChronoUnit.DAYS), + userId = userId + ) + + for { + _ <- repository.userTokens.create(tokenRequest) + } yield tokenRequest + } +}