Skip to content

Commit

Permalink
[TRELLO-2008] Add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
charlescd committed Oct 2, 2023
1 parent 20a8696 commit 6261d56
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 42 deletions.
72 changes: 31 additions & 41 deletions app/tasks/report/ReportRemindersTask.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class ReportRemindersTask(
): Future[(List[List[UUID]], List[List[UUID]])] = {
logger.info(s"Sending reminders for ${reportsWithUsers.length} reports")
val reportsPerUsers = reportsWithUsers.groupBy(_._2).view.mapValues(_.map(_._1))
val reportsPerCompanyPerUsers = reportsPerUsers.mapValues(_.groupBy(_.companyId)).mapValues(_.values).toMap
val reportsPerCompanyPerUsers = reportsPerUsers.mapValues(_.groupBy(_.companyId)).mapValues(_.values)

for {
successesOrFailuresList <- Future.sequence(reportsPerCompanyPerUsers.toList.flatMap {
Expand All @@ -94,39 +94,45 @@ class ReportRemindersTask(
val (readByPros, notReadByPros) = reports.partition(_.isReadByPro)

for {
readByProsSent <-
if (readByPros.nonEmpty) test(readByPros, users, ProReportsReadReminder, EMAIL_PRO_REMIND_NO_ACTION)
else Future.successful(Right(List.empty))
notReadByProsSent <-
if (notReadByPros.nonEmpty)
test(notReadByPros, users, ProReportsUnreadReminder, EMAIL_PRO_REMIND_NO_READING)
else Future.successful(Right(List.empty))
} yield List(readByProsSent, notReadByProsSent)

readByProsSent <- sendReminderEmailIfAtLeastOneReport(
readByPros,
users,
ProReportsReadReminder,
EMAIL_PRO_REMIND_NO_ACTION
)
notReadByProsSent <- sendReminderEmailIfAtLeastOneReport(
notReadByPros,
users,
ProReportsUnreadReminder,
EMAIL_PRO_REMIND_NO_READING
)
} yield List(readByProsSent, notReadByProsSent).flatten
}
})
(failures, successes) = successesOrFailuresList.flatten.partitionMap(identity)
} yield (failures.filter(_.nonEmpty), successes.filter(_.nonEmpty))
} yield (failures, successes)
}

private def test(
private def sendReminderEmailIfAtLeastOneReport(
reports: List[Report],
users: List[User],
email: (List[EmailAddress], List[Report], Period) => Email,
action: ActionEventValue
) = {
logger.infoWithTitle("report_reminders_task_item", s"Sending reports ${reports.map(_.id)}")
sendReminderEmail(reports, users, email, action).transform {
case Success(_) => Success(Right(reports.map(_.id)))
case Failure(err) =>
logger.errorWithTitle(
"report_reminders_task_item_error",
s"Error sending reminder email for reports ${reports.map(_.id)} to ${users.length} users",
err
)
Success(Left(reports.map(_.id)))
): Future[Option[Either[List[UUID], List[UUID]]]] =
if (reports.nonEmpty) {
sendReminderEmail(reports, users, email, action).transform {
case Success(_) => Success(Some(Right(reports.map(_.id))))
case Failure(err) =>
logger.errorWithTitle(
"report_reminders_task_item_error",
s"Error sending reminder email for reports ${reports.map(_.id)} to ${users.length} users",
err
)
Success(Some(Left(reports.map(_.id))))
}
} else {
Future.successful(None)
}
}

private def shouldSendReminderEmail(
report: Report,
Expand Down Expand Up @@ -155,7 +161,7 @@ class ReportRemindersTask(
): Future[Unit] = {
val emailAddresses = users.map(_.email)

logger.debug(s"Sending reminder email")
logger.infoWithTitle("report_reminders_task_item", s"Sending reports ${reports.map(_.id)}")
for {
_ <- mailService.send(email(emailAddresses, reports, delayBetweenReminderEmails))
_ <- Future.sequence(
Expand All @@ -174,22 +180,6 @@ class ReportRemindersTask(
)
}
)
_ <- Future.sequence(
reports.map { report =>
eventRepository.create(
Event(
UUID.randomUUID(),
Some(report.id),
report.companyId,
None,
OffsetDateTime.now(),
SYSTEM,
action,
stringToDetailsJsValue(s"Relance envoyée à ${emailAddresses.mkString(", ")}")
)
)
}
)
} yield ()
}

Expand Down
87 changes: 87 additions & 0 deletions test/repositories/CRUDRepositorySpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package repositories

import org.specs2.matcher.FutureMatchers
import org.specs2.mutable.Specification
import org.specs2.specification.BeforeAfterAll
import repositories.PostgresProfile.api._
import slick.basic.DatabaseConfig
import slick.jdbc.JdbcProfile
import utils.TestApp

import java.util.UUID
import scala.concurrent.Await
import scala.concurrent.ExecutionContext
import scala.concurrent.duration.Duration

case class TestModel(id: UUID, s: String)

class TestModelTable(tag: Tag) extends DatabaseTable[TestModel](tag, "test_model") {
def s = column[String]("s")

override def * = (id, s) <> ((TestModel.apply _).tupled, TestModel.unapply)
}

object TestModelTable {
val table = TableQuery[TestModelTable]

}

class CRUDRepositorySpec extends Specification with FutureMatchers with BeforeAfterAll {

val (app, components) = TestApp.buildApp()
implicit val ec = components.executionContext
val db = components.dbConfig.db

val repository = new CRUDRepository[TestModelTable, TestModel]() {
override val table = TestModelTable.table
implicit override val ec: ExecutionContext = components.executionContext
override val dbConfig: DatabaseConfig[JdbcProfile] = components.dbConfig
}

override def beforeAll(): Unit =
Await.result(db.run(TestModelTable.table.schema.create), Duration.Inf)

override def afterAll(): Unit =
Await.result(db.run(TestModelTable.table.schema.drop), Duration.Inf)

"CRUDRepository" should {
"create and delete a model" in {
val id = UUID.randomUUID()
val s = UUID.randomUUID().toString
for {
afterCreate <- repository.create(TestModel(id, s))
get1 <- repository.get(id)
_ <- repository.delete(id)
get2 <- repository.get(id)
} yield (afterCreate shouldEqual TestModel(id, s)) &&
(get1 shouldEqual Some(TestModel(id, s))) &&
(get2 shouldEqual None)
}

"update a model" in {
val id = UUID.randomUUID()
UUID.randomUUID().toString
val s2 = UUID.randomUUID().toString
for {
_ <- repository.create(TestModel(id, s2))
_ <- repository.update(id, TestModel(id, s2))
get <- repository.get(id)
_ <- repository.delete(id)
} yield get shouldEqual Some(TestModel(id, s2))
}

"createOrUpdate a model and list models" in {
val id1 = UUID.randomUUID()
val id2 = UUID.randomUUID()
val s0 = UUID.randomUUID().toString
val s1 = UUID.randomUUID().toString
val s2 = UUID.randomUUID().toString
for {
_ <- repository.createOrUpdate(TestModel(id1, s0))
_ <- repository.createOrUpdate(TestModel(id2, s1))
_ <- repository.createOrUpdate(TestModel(id2, s2))
list <- repository.list()
} yield list shouldEqual List(TestModel(id1, s0), TestModel(id2, s2))
}
}
}
47 changes: 47 additions & 0 deletions test/repositories/ConsumerRepositorySpec.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package repositories

import org.specs2.concurrent.ExecutionEnv
import org.specs2.matcher.FutureMatchers
import org.specs2.matcher.TraversableMatchers
import org.specs2.mutable
import org.specs2.specification.BeforeAfterAll
import utils.Fixtures
import utils.TestApp

import java.time.OffsetDateTime
import scala.concurrent.Await
import scala.concurrent.duration.Duration

class ConsumerRepositorySpec(implicit ee: ExecutionEnv)
extends mutable.Specification
with TraversableMatchers
with FutureMatchers
with BeforeAfterAll {

val (app, components) = TestApp.buildApp()

val consumer = Fixtures.genConsumer.sample.get
val deletedConsumer = Fixtures.genConsumer.sample.get.copy(deleteDate = Some(OffsetDateTime.now()))

"ConsumerRepository" should {
"getAll" should {
"exclude soft deleted users" in {
for {
res <- components.consumerRepository.getAll()
} yield res.map(_.id) shouldEqual Seq(consumer.id)
}
}
}

override def beforeAll(): Unit = {
Await.result(components.consumerRepository.create(consumer), Duration.Inf)
Await.result(components.consumerRepository.create(deletedConsumer), Duration.Inf)
()
}

override def afterAll(): Unit = {
Await.result(components.consumerRepository.delete(consumer.id), Duration.Inf)
Await.result(components.consumerRepository.delete(deletedConsumer.id), Duration.Inf)
()
}
}
71 changes: 70 additions & 1 deletion test/repositories/ReportRepositorySpec.scala
Original file line number Diff line number Diff line change
@@ -1,21 +1,26 @@
package repositories

import models.report.ReportFilter
import models.report.ReportTag
import models.report.ReportsCountBySubcategoriesFilter
import models.report.reportmetadata.Os
import models.report.reportmetadata.ReportMetadata
import org.specs2.concurrent.ExecutionEnv
import org.specs2.matcher.FutureMatchers
import org.specs2.matcher.TraversableMatchers
import org.specs2.mutable
import org.specs2.specification.BeforeAfterAll
import utils.Fixtures
import utils.TestApp

import java.util.Locale
import scala.concurrent.Await
import scala.concurrent.duration.Duration

class ReportRepositorySpec(implicit ee: ExecutionEnv)
extends mutable.Specification
with FutureMatchers
with TraversableMatchers
with BeforeAfterAll {

val (app, components) = TestApp.buildApp()
Expand All @@ -26,6 +31,8 @@ class ReportRepositorySpec(implicit ee: ExecutionEnv)
.sample
.get
.copy(
category = "AchatMagasin",
subcategories = List("a", "b", "c"),
contactAgreement = false,
consumerReferenceNumber = Some("anonymousReference"),
firstName = "anonymousFirstName",
Expand All @@ -36,6 +43,8 @@ class ReportRepositorySpec(implicit ee: ExecutionEnv)
.sample
.get
.copy(
category = "AchatMagasin",
subcategories = List("a", "b", "c"),
contactAgreement = true,
consumerReferenceNumber = Some("reference"),
firstName = "firstName",
Expand All @@ -46,12 +55,45 @@ class ReportRepositorySpec(implicit ee: ExecutionEnv)
.genReportForCompany(company)
.sample
.get
.copy(
category = "AchatInternet",
subcategories = List("a", "b", "c")
)

val report3 = Fixtures
.genReportForCompany(company)
.sample
.get
.copy(
category = "AchatInternet",
subcategories = List("a", "b", "d")
)

val report4 = Fixtures
.genReportForCompany(company)
.sample
.get
.copy(
category = "AchatMagasin",
subcategories = List("a", "b", "c"),
tags = List(ReportTag.ReponseConso),
phone = Some("0102030405")
)

val englishReport = Fixtures
.genReportForCompany(company)
.sample
.get
.copy(lang = Some(Locale.ENGLISH))

override def beforeAll(): Unit = {
Await.result(components.companyRepository.create(company), Duration.Inf)
Await.result(components.reportRepository.create(report), Duration.Inf)
Await.result(components.reportRepository.create(anonymousReport), Duration.Inf)
Await.result(components.reportRepository.create(report2), Duration.Inf)
Await.result(components.reportRepository.create(report3), Duration.Inf)
Await.result(components.reportRepository.create(report4), Duration.Inf)
Await.result(components.reportRepository.create(englishReport), Duration.Inf)
Await.result(
components.reportMetadataRepository.create(ReportMetadata(report2.id, false, Some(Os.Ios))),
Duration.Inf
Expand All @@ -63,8 +105,11 @@ class ReportRepositorySpec(implicit ee: ExecutionEnv)
override def afterAll(): Unit = {
Await.result(components.reportRepository.delete(report.id), Duration.Inf)
Await.result(components.reportRepository.delete(anonymousReport.id), Duration.Inf)
Await.result(components.companyRepository.delete(company.id), Duration.Inf)
Await.result(components.reportRepository.delete(report2.id), Duration.Inf)
Await.result(components.reportRepository.delete(report3.id), Duration.Inf)
Await.result(components.reportRepository.delete(report4.id), Duration.Inf)
Await.result(components.reportRepository.delete(englishReport.id), Duration.Inf)
Await.result(components.companyRepository.delete(company.id), Duration.Inf)

()
}
Expand Down Expand Up @@ -92,6 +137,30 @@ class ReportRepositorySpec(implicit ee: ExecutionEnv)
} yield (a.entities must haveLength(1)) && (b.entities must haveLength(1))
}
}

"reportsCountBySubcategories" should {
"fetch french jobs" in {
for {
res <- components.reportRepository.reportsCountBySubcategories(
ReportsCountBySubcategoriesFilter(),
Locale.FRENCH
)
} yield res should containTheSameElementsAs(
Seq(
("AchatInternet", List("a", "b", "c"), 1, 0),
("AchatInternet", List("a", "b", "d"), 1, 0),
("AchatMagasin", List("a", "b", "c"), 3, 1)
)
)
}
}

"getPhoneReports" in {
for {
res <- components.reportRepository.getPhoneReports(None, None)
} yield res should containTheSameElementsAs(List(report4))
}

"deleteReport" should {
"work when metadata exist and delete cascade" in {
components.reportRepository.delete(report2.id).map(_ mustEqual 1)
Expand Down
10 changes: 10 additions & 0 deletions test/utils/Fixtures.scala
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ object Fixtures {

val genGender = Gen.oneOf(Some(Gender.Female), Some(Gender.Male), None)

val genConsumer = for {
id <- arbitrary[UUID]
name <- arbString.arbitrary
apiKey <- arbString.arbitrary
} yield Consumer(
id = id,
name = name,
apiKey = apiKey
)

val genUser = for {
id <- arbitrary[UUID]
password <- arbString.arbitrary
Expand Down

0 comments on commit 6261d56

Please sign in to comment.