Browse Source

chore: to add some debug logging

master
Christof Nolle 1 year ago
parent
commit
34d800f6c9

+ 3
- 0
src/main/scala/de/codingchallenge/DependencyInjectionModule.scala View File

@@ -12,8 +12,11 @@ import de.codingchallenge.repositories.{ArticleRepository, ProductExportReposito
import de.codingchallenge.services.ArticleExportService
import io.prometheus.client.CollectorRegistry

import scala.concurrent.ExecutionContext

trait DependencyInjectionModule extends LoggingModule {

implicit val ec: ExecutionContext = ExecutionContext.global
lazy val environment = wire[Environment]

lazy val routes = wire[Routes]

+ 2
- 2
src/main/scala/de/codingchallenge/models/Article.scala View File

@@ -12,7 +12,7 @@ import scala.util.{Success, Try}
* @param price the articles price
* @param stock the current stock
*/
case class Article(id: String, productId: String, name: String, description: String, price: Float, stock: Int)
case class Article(id: String, productId: String, name: String, description: Option[String], price: Float, stock: Int)

object Article {

@@ -20,7 +20,7 @@ object Article {
* Reads an article from a sequence of columns. Returns an Option with article in success case
*/
implicit val csvColumnReads: CsvColumnReads[Article] = (s: Seq[String]) =>
Try{ (s.head, s(1), s(2), s(3), s(4).toFloat, s(5).toInt) } match {
Try{ (s.head, s(1), s(2), Try(s(3)).toOption, s(4).toFloat, s(5).toInt) } match {
case Success(t) => Some((Article.apply _).tupled(t))
case _ => None
}

+ 1
- 1
src/main/scala/de/codingchallenge/models/ProductExport.scala View File

@@ -12,7 +12,7 @@ object ProductExport{
def apply(a: Article, stockSum: Int): ProductExport = new ProductExport(
productId = a.productId,
name = a.name,
description = a.description,
description = a.description.getOrElse(""),
price = a.price,
stockSum = stockSum
)

+ 4
- 4
src/main/scala/de/codingchallenge/repositories/ArticleRepository.scala View File

@@ -13,13 +13,13 @@ import de.codingchallenge.models.Article

class ArticleRepository(actorSystem: ActorSystem) extends LazyLogging{

implicit val as = actorSystem
private implicit val as = actorSystem

// might be a good idea to make that value configurable
val baseUrl: String = "http://localhost:8080"

lazy val connection = Http().superPool[NotUsed]()

def getArticles(limit: Int): Source[Article, _] = Source.fromFuture(
def getArticles(limit: Int): Source[Article, NotUsed] = Source.fromFuture(
Http()
.singleRequest(HttpRequest(uri = s"$baseUrl/articles/$limit"))
).flatMapConcat(res =>
@@ -34,7 +34,7 @@ class ArticleRepository(actorSystem: ActorSystem) extends LazyLogging{
val articleFlow: Flow[ByteString, Article, NotUsed] = Flow[ByteString]
.map(_.utf8String)
.drop(1)
.map{e => logger.info(s"CSV string: $e"); e}
.map{e => logger.info(s"Parsing CSV string: $e"); e}
.map(_.csvToOptOf[Article])
.map{
case Some(a) => a

+ 23
- 9
src/main/scala/de/codingchallenge/repositories/ProductExportRepository.scala View File

@@ -1,5 +1,6 @@
package de.codingchallenge.repositories

import akka.NotUsed
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model.HttpEntity.Chunked
@@ -10,32 +11,45 @@ import com.typesafe.scalalogging.LazyLogging
import de.codingchallenge.csv.CsvOps._
import de.codingchallenge.models.ProductExport

import scala.concurrent.Future
import scala.concurrent.{ExecutionContext, Future}

class ProductExportRepository(actorSystem: ActorSystem) extends LazyLogging {
class ProductExportRepository(actorSystem: ActorSystem)(implicit ec: ExecutionContext) extends LazyLogging {

val headerLine = "produktId|name|beschreibung|preis|summeBestand\n"
private implicit val as: ActorSystem = actorSystem

val headerLine = "produktId|name|beschreibung|preis|summeBestand"

val baseUrl = "http://localhost:8080"

def add(p: Source[ProductExport, _], articlesSize: Int): Future[HttpResponse] = {
def add(p: Source[ProductExport, NotUsed], articlesSize: Int): Future[HttpResponse] = {

val sourceWithHeader = p.via(csvFlow)
.prepend(Source.single(headerLine))
.intersperse("\n")
.map(ByteString.apply)

// it did not work with charset information
val entity = Chunked.fromData(
ContentType.WithMissingCharset(MediaTypes.`text/csv`),
p.via(csvFlow)
.prepend(Source.single(ByteString(headerLine)))
sourceWithHeader
)

Http()(actorSystem)
Http()
.singleRequest(
HttpRequest(
method = HttpMethods.PUT,
uri = s"$baseUrl/products/$articlesSize",
entity = entity))
.map{res =>
logger.info(s"Server responded with $res")
res
}
}

private val csvFlow: Flow[ProductExport, ByteString, Any] =
Flow.fromFunction(p => ByteString(p.toCsvLine))
private val csvFlow: Flow[ProductExport, String, NotUsed] =
Flow.fromFunction{p =>
logger.info(s"processing export record $p")
p.toCsvLine
}

}

+ 1
- 1
src/main/scala/de/codingchallenge/services/ArticleExportService.scala View File

@@ -31,7 +31,7 @@ class ArticleExportService(
*
* @return
*/
def exportArticles(): Future[HttpResponse] = productExportRepository.add(Source.fromGraph(
def exportArticles(): Future[HttpResponse] = productExportRepository.add(Source.fromGraph[ProductExport, NotUsed](
articleRepository
.getArticles(productsSize)
.filter(_.stock > 0)

+ 0
- 1
src/test/scala/de/codingchallenge/csv/CsvOpsSpec.scala View File

@@ -9,7 +9,6 @@ class CsvOpsSpec extends WordSpec with MustMatchers{

case class CsvTestData(s: String, d: Double)
implicit val csvReads: CsvColumnReads[CsvTestData] = (columns: Seq[String]) => {
println(columns)
Try{(columns.head, columns(1).toDouble)} match{
case Success((s: String, d: Double)) => Some(CsvTestData(s,d))
case _ => None

+ 104
- 2
src/test/scala/de/codingchallenge/fixtures/ArticleFixture.scala View File

@@ -8,7 +8,7 @@ trait ArticleFixture {
id = "id",
productId = "productId",
name = "name",
description = "desc",
description = Some("desc"),
price = 1,
stock = 0)

@@ -16,9 +16,111 @@ trait ArticleFixture {
id = "cheapest",
productId = "productId",
name = "cheapestArticle",
description = "cheapestArticleDesc",
description = Some("cheapestArticleDesc"),
price = 0,
stock = 1)

val anotherArticle = articleUnavailable.copy(price = 1, stock = 5)

val sampleData: Seq[String] =
"""A-U0xzQacF|P-U0xzQacF|EELDPYL||72.17|2
A-CxzQacFC|P-U0xzQacF|LDPYLMEMU YH SZQJVDEAMG|mnlHhk|7.72|6
A-0xzQacFC|P-U0xzQacF|LDPYLMEMU YH SZQJVDEAMG|mnlHhk|7.72|6
A-6TAYX4Ac|P-U0xzQacF|QFBC ELDP||94.22|0
A-tAYX4AcF|P-U0xzQacF|EELDPYL||72.17|2
A-xzQacFC7|P-U0xzQacF|YLM|yuzjdAgfm wwfkgu|92.08|1
A-TAYX4AcF|P-U0xzQacF|EELDPYL||72.17|2
A-XzQacFC7|P-U0xzQacF|YLM|yuzjdAgfm wwfkgu|92.08|1
A-AYX4AcFC|P-U0xzQacF|LDPYLMEMU YH SZQJVDEAMG|mnlHhk|7.72|6
A-zQacFC7P|P-U0xzQacF|M|yuzjdAgfm wwfkgu|92.08|1
A-YX4AcFC7|P-U0xzQacF|YLM|yuzjdAgfm wwfkgu|92.08|1
A-qacFC7Pe|P-U0xzQacF|XYHUSZQJV|mtbswwf gusiukA wllbkxklo|21.62|4
A-X4AcFC7P|P-U0xzQacF|M|yuzjdAgfm wwfkgu|92.08|1
A-QacFC7Pe|P-U0xzQacF|XYHUSZQJV|mtbswwf gusiukA wllbkxklo|21.62|4
A-4AcFC7Pe|P-4AcFC7Pe|XYHUSZQJV|mtbswwf gusiukA wllbkxklo|21.62|4
A-acFC7Pey|P-4AcFC7Pe|SZQJVDEAMG FBMSNWLW FHKKG|siukAyzr bkxklohaa|66.59|3
A-aHqBLPey|P-4AcFC7Pe|SZQJVDEAMG FBMSNWLW FHKKG|siukAyzr bkxklohaa|66.59|3
A-AcFC7Pey|P-4AcFC7Pe|SZQJVDEAMG FBMSNWLW FHKKG|siukAyzr bkxklohaa|66.59|3
A-hqBLPeyU|P-hqBLPeyU|QJVDEAM TFBMSNWLWH HKKGQURSZ|awtwllbkx ebH|16.03|22
A-cFC7PeyU|P-cFC7PeyU|QJVDEAM TFBMSNWLWH HKKGQURSZ|awtwllbkx ebH|16.03|22
A-HqBLPeyU|P-cFC7PeyU|QJVDEAM TFBMSNWLWH HKKGQURSZ|awtwllbkx ebH|16.03|22
A-CFC7PeyU|P-cFC7PeyU|QJVDEAM TFBMSNWLWH HKKGQURSZ|awtwllbkx ebH|16.03|22
A-qBLPeyUj|P-cFC7PeyU|EAMGTF MSNWLW|kgusiukAy llbkxkloha cplqlqxyJw yqscty XcpvAlqswj|15.66|1
A-FC7PeyUj|P-FC7PeyUj|EAMGTF MSNWLW|kgusiukAy llbkxkloha cplqlqxyJw yqscty XcpvAlqswj|15.66|1
A-QBLPeyUj|P-FC7PeyUj|EAMGTF MSNWLW|kgusiukAy llbkxkloha cplqlqxyJw yqscty XcpvAlqswj|15.66|1
A-c7PeyUjD|P-FC7PeyUj|MGT|swwfkg rzDawtwl vvvjebHd aenb aXkcwJyqsc|77.34|17
A-BLPeyUjD|P-FC7PeyUj|MGT|swwfkg rzDawtwl vvvjebHd aenb aXkcwJyqsc|77.34|17
A-C7PeyUjD|P-C7PeyUjD|MGT|swwfkg rzDawtwl vvvjebHd aenb aXkcwJyqsc|77.34|17
A-LPeyUjDg|P-C7PeyUjD|BMSNWL HFH||45.85|0
A-7PeyUjDg|P-C7PeyUjD|BMSNWL HFH||45.85|0
A-peyUjDgF|P-C7PeyUjD|SN L|hkqrz u wtwllbkxkl Hdwcpl|87.72|1
A-DYMxSQVE|P-C7PeyUjD|GTFB|wwfkgu zDawtw|84.12|7
A-PeyUjDgF|P-C7PeyUjD|SN L|hkqrz u wtwllbkxkl Hdwcpl|87.72|1
A-YMxSQVEt|P-YMxSQVEt|MSNWLW FHKKG URSZIDUA|twllb v klohaa plqlqxyJw|8.03|37
A-eyUjDgFM|P-eyUjDgFM|W|fkg rzDawtwl vvvjebHd|19.56|9
A-MxSQVEtB|P-eyUjDgFM|NWLWHF KGQURSZ D||62.12|0
A-2hqVEtBw|P-2hqVEtBw|HFH||45.85|0
A-xSQVEtBw|P-2hqVEtBw|HFH||45.85|0
A-yUjDgFMl|P-yUjDgFMl|FHKKG URSZIDUA|twllb v klohaa plqlqxyJw|8.03|37
A-hqVEtBwW|P-hqVEtBwW|HKKGQURSZ D AKW||2.31|0
A-YUjDgFMl|P-hqVEtBwW|FHKKG URSZIDUA|twllb v klohaa plqlqxyJw|8.03|37
A-SQVEtBwW|P-hqVEtBwW|HKKGQURSZ D AKW||2.31|0
A-UjDgFMlh|P-hqVEtBwW|GQURSZIDU|Ay llbkxkloha|95.28|1
A-qVEtBwWF|P-hqVEtBwW|KGQURSZ D||62.12|0
A-jDgFMlhq|P-hqVEtBwW|SZIDUA WA YWZLRLVBV||29.92|50
A-QVEtBwWF|P-hqVEtBwW|KGQURSZ D||62.12|0
A-dgFMlhqz|P-hqVEtBwW|UAKWATYWZ LVBVKVXJ LBOHHDAWAC|lqlqxyJwv PUpr XcpvAlqswj nlnzjmkv|24.45|2
A-VEtBwWFK|P-hqVEtBwW|URSZIDUA WA YWZLRLVBV||29.92|50
A-DgFMlhqz|P-hqVEtBwW|UAKWATYWZ LVBVKVXJ LBOHHDAWAC|lqlqxyJwv PUpr XcpvAlqswj nlnzjmkv|24.45|2
A-EtBwWFKu|P-hqVEtBwW|ZIDU|Ay llbkxkloha|95.28|1
A-gFMlhqza|P-hqVEtBwW|ATYWZ LVBVKVXJ|bHdwcplqlq kcwJyqsc rdXcpv W|88.45|7
A-tBwWFKuS|P-hqVEtBwW|D||62.12|0
A-fMlhqza2|P-fMlhqza2|WZLRLV VKVXJKEL|haaenbiaX|27.79|0
A-bwWFKuSI|P-bwWFKuSI|AKW YWZLRLVBV||29.92|50
A-FMlhqza2|P-FMlhqza2|WZLRLV VKVXJKEL|haaenbiaX|27.79|0
A-BwWFKuSI|P-FMlhqza2|AKW YWZLRLVBV||29.92|50
A-Mlhqza2Y|P-FMlhqza2|LRLV VKVXJKEL OHHDAW|plqlqxyJw yqscty XcpvAlqswj nlnzjmkv|24.45|2
A-wWFKuSIU|P-wWFKuSIU|WA YWZLRLVBV VXJKELBOHH|aenb|10.51|10
A-lhqza2Yr|P-lhqza2Yr|BVKVXJKELB HHDAWACEP|ql|48.6|10
A-WWFKuSIU|P-lhqza2Yr|WA YWZLRLVBV VXJKELBOHH|aenb|10.51|10
A-HHqza2Yr|P-lhqza2Yr|BVKVXJKELB HHDAWACEP|ql|48.6|10
A-WFKuSIUA|P-lhqza2Yr|WZLRLV VKVXJKEL|haaenbiaX|27.79|0
A-hqza2YrV|P-lhqza2Yr|K X|bHdwcplqlq kcwJyqsc rdXcpv W TqFbn|55.46|0
A-FKuSIUAY|P-lhqza2Yr|LRLV VKVXJKEL OHHDAW|plqlqxyJw yqscty XcpvAlqswj nlnzjmkv|24.45|2
A-Hqza2YrV|P-lhqza2Yr|K X|bHdwcplqlq kcwJyqsc rdXcpv W TqFbn|55.46|0
A-KuSIUAYr|P-lhqza2Yr|BVKVXJKELB HHDAWACEP|ql|48.6|10
A-qza2YrVV|P-lhqza2Yr|X|bHdwcplqlq kcwJyqsc rdXcpv W TqFbn|55.46|0
A-uSIUAYrV|P-uSIUAYrV|K X|bHdwcplqlq kcwJyqsc rdXcpv W TqFbn|55.46|0
A-rDwwLLBK|P-uSIUAYrV|JKELBO HDAWACEPNL|aXkcwJyqsc rdXcpv W|88.45|7
A-sIUAYrVV|P-sIUAYrVV|X|bHdwcplqlq kcwJyqsc rdXcpv W TqFbn|55.46|0
A-za2YrVVj|P-za2YrVVj|LBOHHDAWAC P|ql|48.6|10
A-SIUAYrVV|P-za2YrVVj|X|bHdwcplqlq kcwJyqsc rdXcpv W TqFbn|55.46|0
A-DwwLLBKX|P-za2YrVVj|LBOHHDAWAC P LBQ||27.63|8
A-IUAYrVVj|P-za2YrVVj|LBOHHDAWAC P|ql|48.6|10
A-a2YrVVjb|P-za2YrVVj|HDAWACEPNL QILAQX|cwJy PUpr XcpvAlqswj|15.66|1
A-UAYrVVjb|P-za2YrVVj|HDAWACEPNL QILAQX|cwJy PUpr XcpvAlqswj|15.66|1
A-wwLLBKXK|P-wwLLBKXK|BOHHDAWA EPNLBQILA|kcwJyqsc rdXcpv|97.51|0
A-AYrVVjbd|P-AYrVVjbd|ACEPNLBQIL QXX||96.39|1
A-2YrVVjbd|P-AYrVVjbd|ACEPNLBQIL QXX||96.39|1
A-yrVVjbdc|P-AYrVVjbd|NLBQILAQX KYCJWWJVYS|UprdXcpvA yTqFbn wzijx vo|93.83|0
A-wLLBKXKo|P-wLLBKXKo|DAWA||73.55|31
A-YrVVjbdc|P-wLLBKXKo|NLBQILAQX KYCJWWJVYS|UprdXcpvA yTqFbn wzijx vo|93.83|0
A-lLBKXKoH|P-lLBKXKoH|WACE NLBQILAQX|cwJy PUpr XcpvAlqswj|15.66|1
A-rVVjbdcl|P-rVVjbdcl|LAQXXKYCJW||8.03|37
A-LLBKXKoH|P-rVVjbdcl|WACE NLBQILAQX|cwJy PUpr XcpvAlqswj|15.66|1
A-RVVjbdcl|P-rVVjbdcl|LAQXXKYCJW||8.03|37
A-LBKXKoHA|P-rVVjbdcl|C P|ql|48.6|10
A-VVjbdclQ|P-VVjbdclQ|A|kcwJyqsc rdXcpv|97.51|0
A-BKXKoHAe|P-VVjbdclQ|LBQ LAQXXKYCJW J|PUpr XcpvAlqswj nlnzjmkv|24.45|2
A-VjbdclQq|P-VVjbdclQ|KYCJWWJVYS|UprdXcpvA yTqFbn wzijx vo|93.83|0
A-KXKoHAeN|P-VVjbdclQ|QILAQX KYCJWWJVYS PSUCP|d|31.34|35
A-jbdclQqX|P-VVjbdclQ|CJ|v PUpr XcpvAlqswj nlnzjmkv|24.45|2
A-XKoHAeNB|P-XKoHAeNB|LAQXXKYCJW J YSQPS||22.28|49
A-JbdclQqX|P-XKoHAeNB|CJ|v PUpr XcpvAlqswj nlnzjmkv|24.45|2
A-KoHAeNBa|P-XKoHAeNB|XKYCJWWJ YSQPS C|yydqpgW TqFbn wzijx vo gTro|12.86|2
A-bdclQqXJ|P-XKoHAeNB|J YSQPS||22.28|49
A-oHAeNBak|P-XKoHAeNB|JWWJVYSQPS C TRYDYX|pvAlqsw bnln ijxmdog roqumthtp lijqubnzz|97.32|24
A-BdclQqXJ|P-BdclQqXJ|J YSQPS||22.28|49
A-OHAeNBak|P-BdclQqXJ|JWWJVYSQPS C TRYDYX|pvAlqsw bnln ijxmdog roqumthtp lijqubnzz|97.32|24
A-dclQqXJ7|P-BdclQqXJ|QPSU||77.34|17""".split("\n").map(_.trim)
}

+ 10
- 2
src/test/scala/de/codingchallenge/models/ArticleSpec.scala View File

@@ -2,19 +2,27 @@ package de.codingchallenge.models

import de.codingchallenge.BaseSpec
import de.codingchallenge.csv.CsvOps._
import de.codingchallenge.fixtures.ArticleFixture

class ArticleSpec extends BaseSpec {

"The Article" must {
"parse from sample" in {
"parse fields as expecte" in {
val sampleCsv = "A-UhnpVjCE|P-NhImbQSB|CKVTFO LCCOR TFIAZTP|lxqjlivf dppzKc|79.54|0"
sampleCsv.csvToOptOf[Article].get mustBe Article(
"A-UhnpVjCE",
"P-NhImbQSB",
"CKVTFO LCCOR TFIAZTP",
"lxqjlivf dppzKc",
Some("lxqjlivf dppzKc"),
79.54f,
0)
}
"parse a sample data" in new ArticleFixture {
sampleData
.foreach(row => {
row.csvToOptOf[Article].get mustBe a[Article]
}
)
}
}
}

+ 11
- 5
src/test/scala/de/codingchallenge/repositories/ProductExportRepositorySpec.scala View File

@@ -2,9 +2,10 @@ package de.codingchallenge.repositories

import akka.http.scaladsl.model.StatusCodes
import akka.stream.scaladsl.{Sink, Source}
import de.codingchallenge.fixtures.ProductExportFixture
import de.codingchallenge.models.Article
import de.codingchallenge.{AkkaSpec, BaseSpec}
import de.codingchallenge.fixtures.{ArticleFixture, ProductExportFixture}
import de.codingchallenge.models.{Article, ProductExport}
import de.codingchallenge.csv.CsvOps._
import de.codingchallenge.{AkkaSpec, BaseSpec, models}

import scala.concurrent.Await
import scala.concurrent.duration._
@@ -12,13 +13,18 @@ import scala.concurrent.duration._
/**
* Honestly this is kind of an integration tests running against the Demo Server
*/
class ProductExportRepositorySpec extends BaseSpec with AkkaSpec with ProductExportFixture {
class ProductExportRepositorySpec extends BaseSpec with AkkaSpec with ProductExportFixture with ArticleFixture {

"The ProductExportRepository" must {
"put product reports as expected" in {
"put a single report" in {
val repo = new ProductExportRepository(system)
Await.result(repo.add(Source.single(productExport), 1), 2.second).status mustBe StatusCodes.OK
}
"put multiple reports" in {
val repo = new ProductExportRepository(system)
val articles = sampleData.map(_.csvToOptOf[Article].get).toList.map(e => models.ProductExport(e, 1))
Await.result(repo.add(Source(articles), 1), 2.second).status mustBe StatusCodes.OK
}
}

}

+ 21
- 3
src/test/scala/de/codingchallenge/services/ArticleExportServiceSpec.scala View File

@@ -1,9 +1,10 @@
package de.codingchallenge.services

import akka.NotUsed
import akka.http.scaladsl.model.HttpResponse
import akka.stream.scaladsl.{Sink, Source}
import de.codingchallenge.fixtures.{ArticleFixture, ProductExportFixture}
import de.codingchallenge.models.ProductExport
import de.codingchallenge.models.{Article, ProductExport}
import de.codingchallenge.repositories.{ArticleRepository, ProductExportRepository}
import de.codingchallenge.{AkkaSpec, BaseSpec}
import org.mockito.ArgumentCaptor
@@ -13,6 +14,7 @@ import scala.concurrent.{Await, Future}
import org.mockito.Mockito._
import org.mockito.ArgumentMatchers._
import org.mockito.internal.verification.argumentmatching.ArgumentMatchingTool
import de.codingchallenge.csv.CsvOps._

class ArticleExportServiceSpec extends BaseSpec with AkkaSpec{

@@ -31,7 +33,7 @@ class ArticleExportServiceSpec extends BaseSpec with AkkaSpec{
.thenReturn(Future.successful(HttpResponse()))

Await.result(service.exportArticles(), 5.second)
val sourceCaptor: ArgumentCaptor[Source[ProductExport, _]] = ArgumentCaptor.forClass(classOf[Source[ProductExport, _]])
val sourceCaptor: ArgumentCaptor[Source[ProductExport, NotUsed]] = ArgumentCaptor.forClass(classOf[Source[ProductExport, NotUsed]])
verify(productExportRepositoryMock).add(sourceCaptor.capture(), any())
Await.result(sourceCaptor.getValue.runWith(Sink.headOption), 1.second) mustBe None
}
@@ -43,9 +45,25 @@ class ArticleExportServiceSpec extends BaseSpec with AkkaSpec{
.thenReturn(Future.successful(HttpResponse()))

Await.result(service.exportArticles(), 5.second)
val sourceCaptor: ArgumentCaptor[Source[ProductExport, _]] = ArgumentCaptor.forClass(classOf[Source[ProductExport, _]])
val sourceCaptor: ArgumentCaptor[Source[ProductExport, NotUsed]] = ArgumentCaptor.forClass(classOf[Source[ProductExport, NotUsed]])
verify(productExportRepositoryMock).add(sourceCaptor.capture(), any())
Await.result(sourceCaptor.getValue.runWith(Sink.head), 1.second) mustBe productExport
}
"pass sample data as expected" in new TestSetup with ArticleFixture {

val articles = sampleData.map(_.csvToOptOf[Article].get).toList
doReturn(Source(articles), Nil: _*)
.when(articleRepositoryMock)
.getArticles(100)
when(productExportRepositoryMock.add(any(), any()))
.thenReturn(Future.successful(HttpResponse()))

Await.result(service.exportArticles(), 5.second)
val sourceCaptor: ArgumentCaptor[Source[ProductExport, NotUsed]] = ArgumentCaptor.forClass(classOf[Source[ProductExport, NotUsed]])
verify(productExportRepositoryMock).add(sourceCaptor.capture(), any())
Await.result(sourceCaptor.getValue.runWith(Sink.seq), 1.second).foreach { e =>
e mustBe a[ProductExport]
}
}
}
}

Loading…
Cancel
Save