Unit test or integration test for loading configuration from kubernetes secret using ciris-kubernetes

3/26/2019

Hello scala community,

I'm using ciris-kubernetes to inject credentials and certificates from kubernetes secrets. While it works like a charm, I am wondering what would be the best way to unit test or write an intergration test for this functionality?

More specifically, if one of the primary objectives of configuration as code is to write tests for it, shouldn't that aspect be given more importance?

Here's my case class for holding configuration

import java.io.File 
import ciris.Secret 

final case class SAMLCertificateConfiguration(publicKey: Secret[File], privateKey: Secret[File], password: Secret[String])

and the configuration loader

object ConfigurationLoader {

  private[this] val log = LoggerFactory getLogger this.getClass

  private def createConfigurationUsingSecret(namespace: NonEmptyString, secretName: NonEmptyString): IO[SAMLCertificateConfiguration] = {

    def getKubernetesSecret: IO[SecretInNamespace[IO]] =
      for {
        apiClient <- defaultApiClient[IO]
      } yield secretInNamespace[IO](namespace, apiClient)

    def createCertificateConfigurationWith(secret: SecretInNamespace[IO]): IO[SAMLCertificateConfiguration] =
      loadConfig(secret[Secret[File]](secretName.value, "public.crt"), secret[Secret[File]](secretName.value, "private.pfx"), secret[Secret[String]](secretName.value, "password")) {
        (publicKey, privateKey, privateKeyPassword) =>
          SAMLCertificateConfiguration(publicKey, privateKey, privateKeyPassword)
      }.orRaiseThrowable

    for {
      secret <- getKubernetesSecret
      samlCertificateConfiguration <- createCertificateConfigurationWith(secret)
    } yield samlCertificateConfiguration

  }

  def loadSAMLCertificateConfiguration: IO[SAMLCertificateConfiguration] =
    loadConfig(
      envF[IO, ApplicationEnvironment]("APPLICATION_ENVIRONMENT")
        .orElse(propF[IO, ApplicationEnvironment]("application.environment"))
        .orNone,
      envF[IO, NonEmptyString]("KUBERNETES_NAMESPACE")
        .orElse(propF[IO, NonEmptyString]("kubernetes.namespace"))
        .orValue("default"),
      envF[IO, NonEmptyString]("KUBERNETES_SECRET_NAME")
        .orElse(propF[IO, NonEmptyString]("kubernetes.secret.name"))
        .orValue("saml-pfx")
    ) { (environment, namespace, secret) =>
      import pp.util.configuration.ApplicationEnvironment._
      log.info(s"Environment: $environment, Kubernetes namespace: $namespace, Kubernetes secret's name: $secret")
      environment match {
        case Some(Test) | Some(Production) =>
          createConfigurationUsingSecret(namespace, secret).unsafeRunSync()
        case _ =>
          createSAMLCertificateConfigurationUsingHOCON
      }
    }.orRaiseThrowable

}

import enumeratum.{Enum, EnumEntry}
import scala.collection.immutable

sealed abstract class ApplicationEnvironment extends EnumEntry

object ApplicationEnvironment extends Enum[ApplicationEnvironment] {
  case object Development extends ApplicationEnvironment
  case object Test extends ApplicationEnvironment
  case object Production extends ApplicationEnvironment
  def values: immutable.IndexedSeq[ApplicationEnvironment] = findValues
}

import ciris._
import lt.dvim.ciris.Hocon._
import com.typesafe.config.ConfigFactory

object DefaultConfigurationLoader {

  def createSAMLCertificateConfigurationUsingHOCON: SAMLCertificateConfiguration = {

    def defaultConfiguration = {
      val fallbackConfiguration = ConfigFactory.parseString("""
                    |saml.certificate {
                    |  privateKey = "/tmp/certificates/private.pfx"
                    |  publicKey = "/tmp/certificates/public.crt"
                    |  password = ""
                    |}
                """.stripMargin)
      ConfigFactory.load().withFallback(fallbackConfiguration)
    }

    def hocon = hoconAt(defaultConfiguration)("saml.certificate")

    loadConfig(hocon[String]("publicKey"), hocon[String]("privateKey"), hocon[String]("password"))((publicKeyPath, privateKeyPath, privateKeyPassword) => {
      import java.nio.file.Paths
      import ciris.Secret
      SAMLCertificateConfiguration(Secret(Paths.get(publicKeyPath).toFile), Secret(Paths.get(privateKeyPath).toFile), Secret(privateKeyPassword))
    }).orThrow()
  }

}

Should one use io.fabric8.kubernetes.client.server.mock.KubernetesServer as shown over here and implicitly inject kubernetes java client into the configuration loader, so that it can be mocked in tests?

-- Viswanath
configuration
integration-testing
kubernetes
scala
unit-testing

0 Answers