Skip to content

Commit

Permalink
Merge pull request #7 from gilcu2/config
Browse files Browse the repository at this point in the history
added config
  • Loading branch information
gilcu2 authored Sep 12, 2023
2 parents 91db817 + dc6dd02 commit 8d1c2c6
Show file tree
Hide file tree
Showing 10 changed files with 107 additions and 38 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.3.0] - 2023-08-12
### Added
- Config

## [0.2.0] - 2023-08-12
### Added
- Bonus services
Expand All @@ -19,3 +23,4 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
[Unreleased]: https://github.com/gilcu2/reviews_service/master
[0.1.0]: https://github.com/gilcu2/reviews_service/releases/tag/0.1.0
[0.2.0]: https://github.com/gilcu2/reviews_service/releases/tag/0.2.0
[0.3.0]: https://github.com/gilcu2/reviews_service/releases/tag/0.3.0
2 changes: 1 addition & 1 deletion bin/get_review.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

ID=${1:-1}

curl -v http://localhost:8080/review/$ID
curl -v http://localhost:8080/api/review/$ID
3 changes: 2 additions & 1 deletion bin/post_review.sh
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#!/bin/bash

curl -v -d '@data/review_sample.json' -H "Content-Type: application/json" -X POST http://localhost:8080/review
curl -v -d '@data/review_sample.json' -H "Content-Type: application/json" \
-X POST http://localhost:8080/api/review
3 changes: 3 additions & 0 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ val MunitCatsEffectVersion = "1.0.7"
val doobieVersion = "1.0.0-RC3"
val h2Version = "2.2.220"
val flywayVersion = "9.22.0"
val PureConfigVersion = "0.17.4"

lazy val root = (project in file("."))
.settings(
Expand All @@ -27,6 +28,8 @@ lazy val root = (project in file("."))
"org.flywaydb" % "flyway-core" % flywayVersion,
"org.scalameta" %% "svm-subs" % "20.2.0",
"ch.qos.logback" % "logback-classic" % LogbackVersion % Runtime,
"com.github.pureconfig" %% "pureconfig" % PureConfigVersion,
"com.github.pureconfig" %% "pureconfig-cats-effect" % PureConfigVersion,
"io.circe" %% "circe-literal" % CirceVersion % "it,test",
"org.scalameta" %% "munit" % MunitVersion % Test,
"org.typelevel" %% "munit-cats-effect-3" % MunitCatsEffectVersion % Test,
Expand Down
12 changes: 12 additions & 0 deletions src/main/resources/application.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
server {
host = "0.0.0.0"
port = 8080
}

database {
driver = "org.h2.Driver"
url = "jdbc:h2:mem:todo;MODE=PostgreSQL;DB_CLOSE_DELAY=-1"
user = "sa"
password = ""
thread-pool-size = 32
}
16 changes: 16 additions & 0 deletions src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- On Windows machines setting withJansi to true enables ANSI
color code interpretation by the Jansi library. This requires
org.fusesource.jansi:jansi:1.8 on the class path. Note that
Unix-based operating systems such as Linux and Mac OS X
support ANSI color codes by default. -->
<withJansi>true</withJansi>
<encoder>
<pattern>[%thread] %highlight(%-5level) %cyan(%logger{15}) - %msg %n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>
33 changes: 17 additions & 16 deletions src/main/scala/Server.scala
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,23 @@ import org.typelevel.log4cats.LoggerFactory
import org.typelevel.log4cats.slf4j.Slf4jFactory
import org.http4s.server.middleware.ErrorAction
import org.http4s.server.middleware.ErrorHandling
import config.Config

object Server {

implicit val loggerFactory: LoggerFactory[IO] = Slf4jFactory.create[IO]

def create(): IO[ExitCode] = {
resources().use(create)
def create(configFile: String = "application.conf"): IO[ExitCode] = {
resources(configFile).use(create)
}



private def create(resources: Resources): IO[ExitCode] = {
for {
_ <- DB.initialize(resources.transactor)
repository = new Repository(resources.transactor)
exitCode <- BlazeServerBuilder[IO]
.bindHttp(8080,"0.0.0.0")
.bindHttp(resources.config.server.port, resources.config.server.host)
.withHttpApp(withErrorLogging(repository))
.serve
.compile
Expand All @@ -35,23 +35,24 @@ object Server {

private def withErrorLogging(repository: Repository): Kleisli[IO, Request[IO], Response[IO]] =
ErrorHandling.Recover.total(
ErrorAction.log(
Router("/api" -> new Routes(repository).routes).orNotFound,
messageFailureLogAction = (t, msg) =>
IO.println(msg) >>
IO.println(t),
serviceErrorLogAction = (t, msg) =>
IO.println(msg) >>
IO.println(t)
ErrorAction.log(
Router("/api" -> new Routes(repository).routes).orNotFound,
messageFailureLogAction = (t, msg) =>
IO.println(msg) >>
IO.println(t),
serviceErrorLogAction = (t, msg) =>
IO.println(msg) >>
IO.println(t)
)
)
)

private def resources(): Resource[IO, Resources] = {
private def resources(configFile: String): Resource[IO, Resources] = {
for {
config <- Config.load(configFile)
transactor <- DB.transactor()
} yield Resources(transactor)
} yield Resources(transactor, config)
}

private case class Resources(transactor: HikariTransactor[IO])
case class Resources(transactor: HikariTransactor[IO], config: Config)

}
20 changes: 20 additions & 0 deletions src/main/scala/config/package.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import cats.effect.{IO, Resource}
import com.typesafe.config.ConfigFactory
import pureconfig._
import pureconfig.generic.auto._
import pureconfig.module.catseffect.syntax._


package object config {
case class ServerConfig(host: String ,port: Int)

case class DatabaseConfig(driver: String, url: String, user: String, password: String, threadPoolSize: Int)

case class Config(server: ServerConfig, database: DatabaseConfig)

object Config {
def load(configFile: String = "application.conf"): Resource[IO, Config] = {
Resource.eval(ConfigSource.fromConfig(ConfigFactory.load(configFile)).loadF[IO, Config]())
}
}
}
8 changes: 8 additions & 0 deletions src/test/resources/test.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include "application.conf"

server {
host = localhost
port = 8081
}

database.url = "jdbc:h2:mem:todo_test;MODE=PostgreSQL;DB_CLOSE_DELAY=-1"
43 changes: 23 additions & 20 deletions src/test/scala/ServerTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import Model.{AirportReview, AirportReviewCount, AirportStats, Review}
import cats.effect.IO
import cats.effect.{ExitCode, IO}
import cats.effect.unsafe.IORuntime
import config.Config
import io.circe.Json
import org.http4s.blaze.client.BlazeClientBuilder
import org.http4s.circe._
Expand All @@ -21,7 +22,11 @@ class ServerTest extends flatspec.AnyFlatSpec with Matchers
with GivenWhenThen with BeforeAndAfterAll with Eventually {
private lazy val client = BlazeClientBuilder[IO].resource

private val rootUrl = s"http://localhost:8080/api"
private val configFile = "test.conf"

private lazy val config = Config.load(configFile).use(config => IO.pure(config)).unsafeRunSync()

private lazy val rootUrl = s"http://${config.server.host}:${config.server.port}/api"

private implicit val runtime: IORuntime = cats.effect.unsafe.IORuntime.global

Expand All @@ -32,7 +37,7 @@ class ServerTest extends flatspec.AnyFlatSpec with Matchers
interval = scaled(Span(100, Millis)))

override def beforeAll(): Unit = {
Server.create().unsafeRunAsync(resultHandler)
Server.create(configFile).unsafeRunAsync(resultHandler)
eventually {
client.use(_.statusFromUri(Uri.unsafeFromString(s"$rootUrl/hello"))).unsafeRunSync() shouldBe Status.Ok
}
Expand Down Expand Up @@ -83,20 +88,20 @@ class ServerTest extends flatspec.AnyFlatSpec with Matchers
val reviews = List(
Review(airport_name = "a1", title = "t1", author = "a1", content = "c1"),
Review(airport_name = "a1", title = "t2", author = "a1", content = "c1"),
Review(airport_name = "a2",title = "t3",author = "a1",content = "c1")
Review(airport_name = "a2", title = "t3", author = "a1", content = "c1")
)
reviews.foreach(r=>{
val r_json=r.asJson
reviews.foreach(r => {
val r_json = r.asJson
val requestPost = Request[IO](method = Method.POST,
uri = Uri.unsafeFromString(s"$rootUrl/review"))
.withEntity(r_json)
client.use(_.expect[Json](requestPost)).unsafeRunSync()
})

And("The expected values")
val expected=List(
AirportReviewCount("a1",2),
AirportReviewCount("a2",1)
val expected = List(
AirportReviewCount("a1", 2),
AirportReviewCount("a2", 1)
)

When("retrieve the stats")
Expand All @@ -114,11 +119,11 @@ class ServerTest extends flatspec.AnyFlatSpec with Matchers
Given("Some reviews in the DB")
val reviews = List(
Review(airport_name = "a3", title = "t1", author = "a1", content = "c1",
overall_rating=Some(6),recommended = Some(1)),
overall_rating = Some(6), recommended = Some(1)),
Review(airport_name = "a3", title = "t2", author = "a1", content = "c1",
overall_rating=Some(4),recommended = Some(1)),
overall_rating = Some(4), recommended = Some(1)),
Review(airport_name = "a3", title = "t3", author = "a1", content = "c1",
overall_rating=Some(2),recommended = Some(0))
overall_rating = Some(2), recommended = Some(0))
)
reviews.foreach(r => {
val r_json = r.asJson
Expand All @@ -129,7 +134,7 @@ class ServerTest extends flatspec.AnyFlatSpec with Matchers
})

And("The expected values")
val expected = AirportStats("a3", 3,4.0,2)
val expected = AirportStats("a3", 3, 4.0, 2)

When("retrieve the stats")
val requestGet = Request[IO](method = Method.GET,
Expand All @@ -144,13 +149,13 @@ class ServerTest extends flatspec.AnyFlatSpec with Matchers

"Server" should "retrieve Reviews of given airport" in {
Given("airport name")
val airport_name="a5"
val airport_name = "a5"

And("Some reviews of this airport in the DB")
val reviews = List(
Review(airport_name = airport_name, title = "t1", author = "a1", content = "c1",
overall_rating=Some(6),recommended = Some(1),
date=Option("1/1/23"), author_country = Option("de")
overall_rating = Some(6), recommended = Some(1),
date = Option("1/1/23"), author_country = Option("de")
),
Review(airport_name = airport_name, title = "t2", author = "a2", content = "c1",
overall_rating = Some(5), recommended = Some(1),
Expand All @@ -167,8 +172,8 @@ class ServerTest extends flatspec.AnyFlatSpec with Matchers

And("The expected values")
val expected = List(
AirportReview(airport_name, 6,"1/1/23","c1","a1","de"),
AirportReview(airport_name, 5,"1/1/23","c1","a2","de")
AirportReview(airport_name, 6, "1/1/23", "c1", "a1", "de"),
AirportReview(airport_name, 5, "1/1/23", "c1", "a2", "de")
)

When("retrieve the reviews")
Expand Down Expand Up @@ -244,7 +249,7 @@ class ServerTest extends flatspec.AnyFlatSpec with Matchers
"""

And("another airport name")
val airport_name="BER"
val airport_name = "BER"

And("The expected result")
val expected = Review(airport_name = "BER", title = "title",
Expand Down Expand Up @@ -274,8 +279,6 @@ class ServerTest extends flatspec.AnyFlatSpec with Matchers
}




private def resultHandler(result: Either[Throwable, ExitCode]): Unit = {
result.left.foreach(t => logger.error("Executing the http server failed", t))
}
Expand Down

0 comments on commit 8d1c2c6

Please sign in to comment.