skip to Main Content

I am new to scala and I am using it with Playframework to build an API.

I have multiple docker containers (API, DB). Also, there is a module where DB configuration are specified. In this configuration, I use docker container name db in setJdbcUrl.
Everything works perfectly when running things within docker containers.

However, I have a healthcheck unit test that tests a route.
This test fails because it cant recognize the URL (as expected), but I am not sure if there is a way to update the fake application in the test to use the correct URL.

The Module

class ReadWriteDB extends ScalaModule {

  @Singleton
  @Provides
  @Named("db.sql.readwrite.quill.context")
  def quillContext(): PostgresJdbcContext[SnakeCase.type] = {
    val ds = new HikariDataSource(DBConnectionConfig.hikariConfig())
    QuillFactory.create(ds, Duration("2m"))
  }

object DBConnectionConfig {
  def hikariConfig(): HikariConfig = {
    val config = new HikariConfig
    config.setDriverClassName("org.postgresql.Driver")
    config.setJdbcUrl("jdbc:postgresql://db:5432/postgres")
//    config.setJdbcUrl("jdbc:postgresql://localhost:5432/postgres")
//    with the commented config, unit test runs correctly
    config.setUsername(...)
    config.setPassword(...)
    config
  }
}

The unit test

class HealthCheckSpec extends PlaySpec with GuiceOneAppPerTest with Injecting {

  "HealthCheck status" should {
    "reply from the router" in {
      // can I edit app to use a different URL here? 
      val request = FakeRequest(GET, "/status")
      val home = route(app, request).get

      status(home) mustBe OK
      contentAsString(home) must include("API is running!")
    }
  }
}

Controller

@Singleton
class HealthCheck @Inject()(val controllerComponents: ControllerComponents) extends BaseController {

  def check(): Action[AnyContent] = Action {
    Ok("API is running!n")
  }
}

Any guidelines would be appreciated.

2

Answers


  1. You have all the tools you need. I would turn the object into a class and use @provides and @singleton like you have in your quillContext, and I’d also pull out the behaviour into a trait and have a method for just is the healthcheck okay:

    trait DBObjectConfig {
        def hikariConfig(): HikariConfig
        def isOK() :Boolean
    }
    
    @provides
    class RealDBConnection extends DBObjectConfig {
      def hikariConfig(): HikariConfig = {
        val config = new HikariConfig
        config.setDriverClassName("org.postgresql.Driver")
        config.setJdbcUrl("jdbc:postgresql://db:5432/postgres")
        config.setJdbcUrl("jdbc:postgresql://localhost:5432/postgres")
        config.setUsername(...)
        config.setPassword(...)
        config
      }
    
      // todo: make something here that's a reliable test.
      def isOK() :Boolean = {
        Option(hakariConfig.getConnection()).isDefined
      }
    }
    
    

    Your healthcheck controller can use isOK() to see if the db is up or not.

    Then in your test, using Guice (your test extends an injector?) you should be able to bind a fake implementation of DBObjectConfig to your app, which will cause your controller to not instantiate a real db connection in the testing environment:

    // inside your tests.
    
    class MockDB extends DBObjectConfig {
        def hikariConfig(): HikariConfig = ??? // implementation not required
        def isOK() :Boolean = true             // fake it being okay.
    }
    
    val application = new GuiceApplicationBuilder()
      .overrides(bind[DBObjectConfig].to[MockDB])
      .build()
    

    Some technique using this general approach should work.

    Login or Signup to reply.
  2. To implement Health Check I would recommend Play-Actuator dependency.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search