Cannot use ready checker and log line receiver together
cb372 opened this issue · 3 comments
cb372 commented
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 commented
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 commented
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 commented
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
}
}
}