From 979ff9e765e3c08501cbd00354a87013853fe796 Mon Sep 17 00:00:00 2001 From: vlad Date: Tue, 19 Jul 2016 15:01:30 -0400 Subject: Unit tests for core code and bug fixes --- src/main/scala/com/drivergrp/core/app.scala | 22 ++++++++------- src/main/scala/com/drivergrp/core/generators.scala | 32 ++++++++++++++++------ src/main/scala/com/drivergrp/core/logging.scala | 7 +++++ src/main/scala/com/drivergrp/core/messages.scala | 2 +- src/main/scala/com/drivergrp/core/rest.scala | 4 +-- src/main/scala/com/drivergrp/core/stats.scala | 3 +- src/main/scala/com/drivergrp/core/time.scala | 8 ++++-- 7 files changed, 52 insertions(+), 26 deletions(-) (limited to 'src/main/scala/com') diff --git a/src/main/scala/com/drivergrp/core/app.scala b/src/main/scala/com/drivergrp/core/app.scala index 13663ab..4639fc0 100644 --- a/src/main/scala/com/drivergrp/core/app.scala +++ b/src/main/scala/com/drivergrp/core/app.scala @@ -52,14 +52,22 @@ object app { } protected def bindHttp(modules: Seq[Module]): Unit = { - import SprayJsonSupport._ - import DefaultJsonProtocol._ - val serviceTypes = modules.flatMap(_.routeTypes) val swaggerService = new Swagger(actorSystem, serviceTypes, config) val swaggerRoutes = swaggerService.routes ~ swaggerService.swaggerUI + val versionRt = versionRoute(version, buildNumber) + + val _ = http.bindAndHandle( + route2HandlerFlow(logRequestResult("log")(modules.map(_.route).foldLeft(versionRt ~ swaggerRoutes)(_ ~ _))), + interface, + port)(materializer) + } - val versionRoute = path("version") { + protected def versionRoute(version: String, buildNumber: Int) = { + import SprayJsonSupport._ + import DefaultJsonProtocol._ + + path("version") { complete( Map( "version" -> version, @@ -67,12 +75,6 @@ object app { "serverTime" -> time.currentTime().millis.toString )) } - - val _ = http.bindAndHandle( - route2HandlerFlow( - logRequestResult("log")(modules.map(_.route).foldLeft(versionRoute ~ swaggerRoutes)(_ ~ _))), - interface, - port)(materializer) } /** diff --git a/src/main/scala/com/drivergrp/core/generators.scala b/src/main/scala/com/drivergrp/core/generators.scala index 6055cd0..a564374 100644 --- a/src/main/scala/com/drivergrp/core/generators.scala +++ b/src/main/scala/com/drivergrp/core/generators.scala @@ -12,12 +12,14 @@ object generators { import random._ private val DefaultMaxLength = 100 + private val StringLetters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ ".toSet - def nextId[T](): Id[T] = Id[T](nextLong()) + def nextId[T](): Id[T] = Id[T](scala.math.abs(nextLong())) def nextName[T](maxLength: Int = DefaultMaxLength): Name[T] = Name[T](nextString(maxLength)) - def nextString(maxLength: Int = DefaultMaxLength) = random.nextString(maxLength) + def nextString(maxLength: Int = DefaultMaxLength): String = + (oneOf[Char](StringLetters) +: arrayOf(oneOf[Char](StringLetters), maxLength - 1)).mkString def nextOption[T](value: => T): Option[T] = if (nextBoolean) Option(value) else None @@ -27,23 +29,35 @@ object generators { def nextTime(): Time = Time(math.abs(nextLong() % System.currentTimeMillis)) - def nextTimeRange(): TimeRange = TimeRange(nextTime(), nextTime()) + def nextTimeRange(): TimeRange = { + val oneTime = nextTime() + val anotherTime = nextTime() + + TimeRange(Time(scala.math.min(oneTime.millis, anotherTime.millis)), + Time(scala.math.max(oneTime.millis, anotherTime.millis))) + } def nextBigDecimal(multiplier: Double = 1000000.00, precision: Int = 2): BigDecimal = BigDecimal(multiplier * nextDouble, new MathContext(precision)) - def oneOf[T](items: Seq[T]): T = items(nextInt(items.size)) + def oneOf[T](items: T*): T = oneOf(items.toSet) + + def oneOf[T](items: Set[T]): T = items.toSeq(nextInt(items.size)) def arrayOf[T: ClassTag](generator: => T, maxLength: Int = DefaultMaxLength): Array[T] = - Array.fill(maxLength)(generator) + Array.fill(nextInt(maxLength))(generator) - def seqOf[T](generator: => T, maxLength: Int = DefaultMaxLength): Seq[T] = Seq.fill(maxLength)(generator) + def seqOf[T](generator: => T, maxLength: Int = DefaultMaxLength): Seq[T] = + Seq.fill(nextInt(maxLength))(generator) - def vectorOf[T](generator: => T, maxLength: Int = DefaultMaxLength): Vector[T] = Vector.fill(maxLength)(generator) + def vectorOf[T](generator: => T, maxLength: Int = DefaultMaxLength): Vector[T] = + Vector.fill(nextInt(maxLength))(generator) - def listOf[T](generator: => T, maxLength: Int = DefaultMaxLength): List[T] = List.fill(maxLength)(generator) + def listOf[T](generator: => T, maxLength: Int = DefaultMaxLength): List[T] = + List.fill(nextInt(maxLength))(generator) - def setOf[T](generator: => T, maxLength: Int = DefaultMaxLength): Set[T] = seqOf(generator, maxLength).toSet + def setOf[T](generator: => T, maxLength: Int = DefaultMaxLength): Set[T] = + seqOf(generator, nextInt(maxLength)).toSet def mapOf[K, V](maxLength: Int, keyGenerator: => K, valueGenerator: => V): Map[K, V] = seqOf(nextPair(keyGenerator, valueGenerator), maxLength).toMap diff --git a/src/main/scala/com/drivergrp/core/logging.scala b/src/main/scala/com/drivergrp/core/logging.scala index a4557e0..126c670 100644 --- a/src/main/scala/com/drivergrp/core/logging.scala +++ b/src/main/scala/com/drivergrp/core/logging.scala @@ -35,6 +35,13 @@ object logging { def debug(marker: Marker, message: String, args: AnyRef*): Unit } + /** + * Logger implementation which uses `com.typesafe.scalalogging.Logger` on the back. + * It redefines the meaning of logging levels to fit to the Driver infrastructure design, + * and as using error and warn, debug and trace was always confusing and mostly done wrong. + * + * @param scalaLogging com.typesafe.scalalogging.Logger which logging will be delegated to + */ class TypesafeScalaLogger(scalaLogging: com.typesafe.scalalogging.Logger) extends Logger { def fatal(message: String): Unit = scalaLogging.error(message) diff --git a/src/main/scala/com/drivergrp/core/messages.scala b/src/main/scala/com/drivergrp/core/messages.scala index a2d6cbd..3a97401 100644 --- a/src/main/scala/com/drivergrp/core/messages.scala +++ b/src/main/scala/com/drivergrp/core/messages.scala @@ -31,7 +31,7 @@ object messages { map.get(key) match { case Some(message) => message case None => - log.error(s"Message with key $key not found for locale " + locale.getDisplayName) + log.error(s"Message with key '$key' not found for locale '${locale.getLanguage}'") key } } diff --git a/src/main/scala/com/drivergrp/core/rest.scala b/src/main/scala/com/drivergrp/core/rest.scala index adbf716..b7edc5b 100644 --- a/src/main/scala/com/drivergrp/core/rest.scala +++ b/src/main/scala/com/drivergrp/core/rest.scala @@ -121,11 +121,11 @@ object rest { /** * "Unwraps" a `OptionT[Future, T]` and runs the inner route after future * completion with the future's value as an extraction of type `Try[T]`. + * Copied akka-http code with added `.run` call on `OptionT`. */ def onComplete[T](optionT: OptionT[Future, T]): Directive1[Try[Option[T]]] = Directive { inner ⇒ ctx ⇒ - import ctx.executionContext - optionT.run.fast.transformWith(t ⇒ inner(Tuple1(t))(ctx)) + optionT.run.fast.transformWith(t ⇒ inner(Tuple1(t))(ctx))(ctx.executionContext) } } diff --git a/src/main/scala/com/drivergrp/core/stats.scala b/src/main/scala/com/drivergrp/core/stats.scala index 904fcc5..cd77f7a 100644 --- a/src/main/scala/com/drivergrp/core/stats.scala +++ b/src/main/scala/com/drivergrp/core/stats.scala @@ -36,7 +36,8 @@ object stats { class LogStats(log: Logger) extends Stats { def recordStats(keys: StatsKeys, interval: TimeRange, value: BigDecimal): Unit = { - log.audit(s"${keys.mkString(".")}(${interval.start.millis}-${interval.end.millis})=${value.toString}") + val valueString = value.bigDecimal.toPlainString + log.audit(s"${keys.mkString(".")}(${interval.start.millis}-${interval.end.millis})=$valueString") } } } diff --git a/src/main/scala/com/drivergrp/core/time.scala b/src/main/scala/com/drivergrp/core/time.scala index dfa63c8..ebe0071 100644 --- a/src/main/scala/com/drivergrp/core/time.scala +++ b/src/main/scala/com/drivergrp/core/time.scala @@ -3,7 +3,7 @@ package com.drivergrp.core import java.text.SimpleDateFormat import java.util.{Calendar, Date, GregorianCalendar} -import scala.concurrent.duration.Duration +import scala.concurrent.duration._ object time { @@ -25,10 +25,12 @@ object time { def isAfter(anotherTime: Time): Boolean = millis > anotherTime.millis - def advanceBy(duration: Duration): Time = Time(millis + duration.length) + def advanceBy(duration: Duration): Time = Time(millis + duration.toMillis) } - final case class TimeRange(start: Time, end: Time) + final case class TimeRange(start: Time, end: Time) { + def duration: Duration = FiniteDuration(end.millis - start.millis, MILLISECONDS) + } implicit def timeOrdering: Ordering[Time] = Ordering.by(_.millis) -- cgit v1.2.3