Skip to content
This repository has been archived by the owner on Apr 29, 2024. It is now read-only.

Commit

Permalink
Merge pull request #97 from aaronp/cucumber
Browse files Browse the repository at this point in the history
Partial fix for issue #44 — added cucumber support
  • Loading branch information
kurtkopchik authored Oct 18, 2017
2 parents 74b6876 + b58ec47 commit 0fdfa13
Show file tree
Hide file tree
Showing 19 changed files with 482 additions and 79 deletions.
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ plugin will attempt to locate it in one of three places with the precedence orde
testCasesJar := // The path to the Jar file containing the tests to execute. This defaults to the Jar file with the tests from the current sbt project.
testCasesPackageTask := // The sbt Task to package the test cases used when running 'dockerComposeTest'. This defaults to the 'packageBin' task in the 'Test' Scope.
testPassUseSpecs2 := // True if Specs2 is to be used to execute the test pass. This defaults to False and ScalaTest is used.
testPassUseCucumber := // True if cucumber is to be used to execute the test pass. This defaults to False and ScalaTest is used.
variablesForSubstitution := // A Map[String,String] of variables to substitute in your docker-compose file. These are substituted substituted by the plugin and not using environment variables.
variablesForSubstitutionTask := // An sbt task that returns a Map[String,String] of variables to substitute in your docker-compose file. These are substituted by the plugin and not using environment variables.
```
Expand Down Expand Up @@ -368,9 +369,17 @@ by setting the following property in build.sbt:
Additionally, you can override the default Specs2 file runner properties as follows:
```
testExecutionExtraConfigTask := Map("filesrunner.verbose" -> s"true")
testExecutionExtraConfigTask := Map("filesrunner.verbose" -> "true")
```
8) [**basic-with-tests-cucumber**](examples/basic-with-tests-cucumber): This project shows how to execute cucumber based test cases
by setting the following property in build.sbt:
```
testPassUseCucumber := true
```
Currently Unsupported Docker Compose Fields
-------------------------------------------
1) "build:" - All docker compose services need to specify an "image:" field.
Expand Down
47 changes: 47 additions & 0 deletions examples/basic-with-tests-cucumber/build.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
name := "basic-cucumber"

version := "1.0.0"

scalaVersion := "2.11.11"

enablePlugins(DockerPlugin, DockerComposePlugin, CucumberPlugin)

libraryDependencies ++= {
val cucumber = List("core", "jvm", "junit").map(suffix =>
"info.cukes" % s"cucumber-$suffix" % "1.2.5" % "test") :+ ("info.cukes" %% "cucumber-scala" % "1.2.5" % "test")

cucumber ::: List(
"org.scalactic" %% "scalactic" % "3.0.4" % "test",
"org.scalatest" %% "scalatest" % "3.0.4" % ("test->*"),
"org.pegdown" % "pegdown" % "1.6.0" % ("test->*"),
"junit" % "junit" % "4.12" % "test"
)
}

CucumberPlugin.glue := "classpath:"
CucumberPlugin.features += "classpath:"

//Set the image creation Task to be the one used by sbt-docker
dockerImageCreationTask := docker.value

testPassUseCucumber := true

imageNames in docker := Seq(ImageName(
repository = name.value.toLowerCase,
tag = Some(version.value))
)

// create a docker file with a file /inputs/example.input
dockerfile in docker := {

val classpath: Classpath = (fullClasspath in Test).value
sLog.value.debug(s"Classpath is ${classpath.files.mkString("\n")}\n")

new Dockerfile {
val dockerAppPath = "/app/"
from("java")
add(classpath.files, dockerAppPath)

entryPoint("java", "-cp", s"$dockerAppPath:$dockerAppPath*", "example.CalculatorServer")
}
}
6 changes: 6 additions & 0 deletions examples/basic-with-tests-cucumber/docker/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
version: '3'
services:
basic-cucumber:
image: basic-cucumber:1.0.0
ports:
- 8080:8080
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
sbt.version=0.13.16
3 changes: 3 additions & 0 deletions examples/basic-with-tests-cucumber/project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
addSbtPlugin("se.marcuslonnberg" % "sbt-docker" % "1.4.1")
addSbtPlugin("com.tapad" % "sbt-docker-compose" % "1.0.29-SNAPSHOT")
addSbtPlugin("com.waioeka.sbt" % "cucumber-plugin" % "0.1.2")
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package example

import java.nio.file.{Files, Path, Paths}

import scala.collection.JavaConverters._

object Calculator {

def main(args: Array[String]): Unit = {
args.toList match {
case Nil => println(s"Usage: Expected either two ints or a file path")
case List(filePath) =>
println(apply(Paths.get(filePath)))
case List(a, b) =>
println(add(a.toInt, b.toInt))
case err => println(s"Usage: Expected either two ints or a file path, but got $err")
}
}

def add(x: Int, y: Int): Int = x + y

def subtract(x: Int, y: Int): Int = x - y

val PlusR = """(\d+)\s*\+\s*(\d+)""".r
val MinusR = """(\d+)\s*-\s*(\d+)""".r

/**
* Evaluates the first line of the input file to be an addition or subtration operation.
*
* This is just added to demonstrate e.g. composing two containers w/ shared volumes
*/
def apply(input: Path): Int = {
Files.readAllLines(input).asScala.headOption match {
case Some(PlusR(a, b)) => add(a.toInt, b.toInt)
case Some(MinusR(a, b)) => subtract(a.toInt, b.toInt)
case _ => sys.error("Whacha talkin' bout, willis?")
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package example

import scala.sys.process._

case class CalculatorClient(hostPort: String) {

def add(x: Int, y: Int) = curl("add", x, y)

def subtract(x: Int, y: Int) = curl("subtract", x, y)

private def curl(path: String, x: Int, y: Int) = {
val url = s"${hostPort}/$path/$x/$y"
println(s"curling $url")
val output = s"curl $url".!!
try {
output.trim.toInt
} catch{
case nfe : NumberFormatException =>
println(output)
throw new Exception(s"$url responded with: >${output}< : $nfe", nfe)
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package example

import java.net.InetSocketAddress

import com.sun.net.httpserver.{HttpExchange, HttpHandler, HttpServer}

object CalculatorServer extends App {
def start(port: Int) = {
val server = HttpServer.create(new InetSocketAddress(port), 0)
server.createContext("/", Handler)
server.start()
server
}


object Handler extends HttpHandler {

val AddInput = """/add/([-0-9]+)/([-0-9]+)/?""".r
val SubtractInput = """/subtract/([-0-9]+)/([-0-9]+)/?""".r

override def handle(ex: HttpExchange): Unit = {
val path = ex.getRequestURI.toString

val resultOpt = path match {
case AddInput(a, b) => Option(Calculator.add(a.toInt, b.toInt))
case SubtractInput(a, b) =>
Option(Calculator.subtract(a.toInt, b.toInt))
case _ => None
}

val replyString = resultOpt match {
case Some(x) =>
val response = x.toString
ex.sendResponseHeaders(200, response.length)
response
case None =>
val response = s"Unknown path: $path"
ex.sendResponseHeaders(404, response.length)
response
}

ex.getResponseBody.write(replyString.getBytes)
}
}


val port = args.headOption.map(_.toInt).getOrElse(8080)
println(s"Starting calculator server on port $port w/ user args ${args.mkString(": [", ",", "]")}")
start(port)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package example

object ClientApp extends App {
val client = CalculatorClient("http://localhost:8080")

println(client.add(5, 6))
println(client.subtract(5, 6))

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
Feature: Remote Server/Client contract

Background:
And a calculator client against http://localhost:8080

Scenario Outline: Addition
Given a remote request to add <lhs> and <rhs>
Then The response should be <sum>
Examples:
| lhs | rhs | sum |
| -1 | 1 | 0 |
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 2 | 3 |

Scenario Outline: Subtraction
Given a remote request to subtract <rhs> from <lhs>
Then The response should be <result>
Examples:
| lhs | rhs | result |
| -1 | 1 | -2 |
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | -1 |
| 1 | 2 | -1 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
Feature: Calculator Operations

Scenario Outline: Addition
Given <lhs> + <rhs>
Then The result should be <sum>
Examples:
| lhs | rhs | sum |
| -1 | 1 | 0 |
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 2 | 3 |

Scenario Outline: Subtraction
Given <lhs> - <rhs>
Then The result should be <result>
Examples:
| lhs | rhs | result |
| -1 | 1 | -2 |
| 0 | 0 | 0 |
| 1 | 0 | 1 |
| 0 | 1 | -1 |
| 1 | 2 | -1 |
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package example

import cucumber.api.scala.{EN, ScalaDsl}
import org.scalatest.Matchers


class CalculatorSteps extends ScalaDsl with EN with Matchers {

var lastResult = Int.MinValue

Given("""^(.+) \+ (.+)$""") { (lhs: Int, rhs: Int) =>
lastResult = Calculator.add(lhs, rhs)
}
Given("""^(.+) - (.+)$""") { (lhs: Int, rhs: Int) =>
lastResult = Calculator.subtract(lhs, rhs)
}
Then("""^The result should be ([-0-9]+)$""") { (expected: Int) =>
lastResult shouldBe expected
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package example

import cucumber.api.CucumberOptions
import cucumber.api.junit.Cucumber
import org.junit.runner.RunWith

@RunWith(classOf[Cucumber])
@CucumberOptions(
features = Array("classpath:"),
glue = Array("classpath:"),
plugin = Array("pretty", "html:target/cucumber/report.html"),
strict = true
)
class CucumberTest
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package example

import cucumber.api.scala.{EN, ScalaDsl}
import org.scalatest.Matchers
import org.scalatest.concurrent.{Eventually, ScalaFutures}

object ServiceSteps {
lazy val defaultStartedService = {
CalculatorServer.start(8080)
}
}

class ServiceSteps extends ScalaDsl with EN with Matchers with ScalaFutures with Eventually {

var lastResult = Int.MinValue
var client: CalculatorClient = null

/**
* This assumes a running service mapped against the host machine at the given location
*/
Given("""^a calculator client against (.+)$""") { hostPort: String =>
client = CalculatorClient(hostPort)

// prove connectivity eagerly within this step
client.add(0, 0) shouldBe 0
}

Given("""^a remote request to add (.+) and (.+)$""") { (lhs: Int, rhs: Int) =>
lastResult = client.add(lhs, rhs)
}
Given("""^a remote request to subtract (.+) from (.+)$""") { (rhs: Int, lhs: Int) =>
lastResult = client.subtract(lhs, rhs)
}
Then("""^The response should be ([-0-9]+)$""") { (expected: Int) =>
lastResult shouldBe expected
}
}
Loading

0 comments on commit 0fdfa13

Please sign in to comment.