All Downloads are FREE. Search and download functionalities are using the official Maven repository.

blended.itestsupport.docker.DockerContainer.scala Maven / Gradle / Ivy

Go to download

Define an integration test API for collaborating blended container(s) using docker as a runtime for the container(s) under test and an Akka based Camel framework to perform the integration tests as pure blackbox tests. Container(s) may be prestarted and discovered (for execution speed) or started by the integration test (for reproducability).

The newest version!
package blended.itestsupport.docker

import java.io.{ByteArrayInputStream, ByteArrayOutputStream, InputStream}

import com.github.dockerjava.api.DockerClient
import com.github.dockerjava.api.model._
import blended.itestsupport.ContainerUnderTest
import com.github.dockerjava.api.command.InspectExecResponse
import com.github.dockerjava.core.command.ExecStartResultCallback
import org.slf4j.LoggerFactory

import scala.util.control.NonFatal

/*
 * Provide a simple wrapper around the excellent docker Java API to create an abstraction suitable for
 * integration tests.
 */

class DockerContainer(cut: ContainerUnderTest)(implicit client: DockerClient) {

  private[this] val logger = LoggerFactory.getLogger(classOf[DockerContainer].getName)

  /**
   * Start the container with a given set of exposed ports. Exposed ports are defined in terms of docker
   * port mappings and map zero or more exposed container ports to physical ports within the hosting
   * OS. The mapping can be injected while starting the container as the port mapping is usually calculated
   * by some manager object that knows about available ports or can determine available ports upon request.
   */
  def startContainer = {
    
    val links : List[Link] = cut.links.map { l => Link.parse(s"${l.container}:${l.hostname}") }
    logger info s"Links for container [${cut.dockerName}] : [$links]."

    val ports : Array[PortBinding] = cut.ports.map { case (name, p) => p.binding }.toArray
    logger info s"Ports for container [${cut.dockerName}] : [${cut.ports}]."

    val env : Array[String] = cut.env.map{ case (k,v) => s"$k=$v" }.toArray

    val containerCmd  = client.createContainerCmd(cut.imgId)
      .withName(cut.dockerName)
      .withTty(true)
      .withPortBindings(ports:_*)
      .withEnv(env:_*)

    if (!links.isEmpty) containerCmd.withLinks(links:_*)
    containerCmd.exec()

    client.startContainerCmd(cut.dockerName).exec()
    this
  }

  def executeCommand(user: String, cmd: String*) : Either[Throwable, (String, ByteArrayOutputStream, ByteArrayOutputStream)] = {

    logger.info(s"Executing cmd [${cmd.foldLeft(""){case (v,e) => v + " " + e }}] for user [$user]")

    try {
      val command = client.execCreateCmd(cut.dockerName)
        .withUser(user)
        .withCmd(cmd:_*)
        .withAttachStdout(true)
        .withAttachStderr(true)

      val execId : String = command.exec().getId()

      val out = new ByteArrayOutputStream()
      val err = new ByteArrayOutputStream()

      val rcb = new ExecStartResultCallback(out, err)

      val startExec = client.execStartCmd(execId).withTty(true)
      startExec.exec[ExecStartResultCallback](rcb)

      Right((execId, out, err))
    } catch {
      case NonFatal(e) => Left(e)
    }
  }

  def inspectExec(id: String) : InspectExecResponse = client.inspectExecCmd(id).withExecId(id).exec()

  def getContainerDirectory(dir: String) : InputStream = {
    logger.info(s"Getting directory [$dir] from container [${cut.ctName}]")
    client.copyArchiveFromContainerCmd(cut.dockerName, dir).exec()
  }

  def writeContainerDirectory(dir: String, content: Array[Byte]) : Boolean = {
    try {
      logger.info(s"Writing archive of size [${content.length}] to directory [$dir] in container [${cut.ctName}]")
      val cmd = client.copyArchiveToContainerCmd(cut.dockerName)
      cmd.withRemotePath(dir).withTarInputStream(new ByteArrayInputStream(content))
      cmd.exec()
      true
    } catch {
      case NonFatal(t) => false
    }
  }

  def containerInfo = client.inspectContainerCmd(cut.dockerName).exec()

  def removeContainer = {
    logger info s"Removing container [${cut.dockerName}] from Docker."
    client.removeContainerCmd(cut.dockerName).withForce(true).withRemoveVolumes(true).exec()
  }
  
  def stopContainer = {
    logger info s"Stopping container [${cut.dockerName}]"
    client.stopContainerCmd(cut.dockerName).exec()
    this
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy