Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot use ready checker and log line receiver together #84

Closed
cb372 opened this issue Jul 5, 2017 · 3 comments
Closed

Cannot use ready checker and log line receiver together #84

cb372 opened this issue Jul 5, 2017 · 3 comments

Comments

@cb372
Copy link
Contributor

cb372 commented Jul 5, 2017

Thanks for a great library!

I've found that I can use either withReadyChecker(DockerReadyChecker.LogLineContains("foo")) or withLogLineReceiver(LogLineReceiver(...)), but I can't use both at the same time. If I add the log line receiver then the ready checker never fires.

Is this expected?

Ideally I'd like to do the following:

  • use a ready checker to wait until the container outputs a certain line
  • use a log line receiver to write the container's output to a file for easy debugging after my tests complete
@Vrolijkx
Copy link

For you interest, I made a workaround for this problem creating a LogLineReciever that can also be used as readyChecker.

import com.whisk.docker.{DockerCommandExecutor, DockerContainerState, DockerReadyChecker, LogLineReceiver}
import grizzled.slf4j.Logging

import scala.concurrent.{ExecutionContext, Promise}

class BufferingLogLineReceiver(linesToKeep: Int = 100) extends LogLineReceiver(true, _ => {}) with Logging {
  import BufferingLogLineReceiver._
  private var buffer = Vector.empty[String]
  private var checkers: List[String => Unit] = List.empty

  override val f = (logLine: String) => {
    addToBuffer(logLine)
    callCheckers(logLine)
  }

  private def addToBuffer(content: String): Unit = {
    buffer = (buffer ++ content.split("\n")) takeRight linesToKeep
  }

  private def callCheckers(content: String): Unit = {
    checkers.foreach(_.apply(content))
  }

  def printAsError(): Unit = {
    if (buffer.length == linesToKeep) {
      error(s"${buffer.mkString("\n")}\n...}")
    } else {
      error(buffer.mkString("\n"))
    }
  }

  def logLineContains(partOfLine: String): DockerReadyChecker = {
    val checker = new SimpleContainsLineReadyCheck(partOfLine)
    checkers = checkers :+ checker.checkLine _
    //process already collected buffer
    buffer.foreach(checker.checkLine)
    checker
  }

}

object BufferingLogLineReceiver {

  private class SimpleContainsLineReadyCheck(partOfLine: String) extends DockerReadyChecker {
    val complete: Promise[Boolean] = Promise()

    override def apply(container: DockerContainerState)(implicit docker: DockerCommandExecutor, ec: ExecutionContext) = {
      complete.future
    }

    def checkLine(line: String): Unit = {
      if(line.toLowerCase.contains(partOfLine.toLowerCase)) {
        complete.trySuccess(true)
      }
    }
  }

}

Hope it helps you for now.

@viktortnk
Copy link
Contributor

I think that LogLineReceiver is limited and the same time not properly working abstraction. I've just created #93 to address it in new version.

@atais
Copy link

atais commented Dec 10, 2018

@Vrolijkx

Defienietly easier to just log it during checking:

case class LogLineAndCheckContains(str: String) extends DockerReadyChecker {
  override def apply(container: DockerContainerState)(implicit docker: DockerCommandExecutor,
                                                      ec: ExecutionContext): Future[Boolean] = {
    for {
      id <- container.id
      _ <- docker.withLogStreamLinesRequirement(id, withErr = true) {
        s =>
          print(s)
          s.contains(str)
      }
    } yield {
      true
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants