Add Play Smoke Test with Java Agent
Adding gradle task & test to compile and start a Play server with the agent, hits a welcome endpoint 200 times as a smoke test.
ADD
dd-java-agent-ittests/play-ittests/play-ittests.gradle
+plugins {
+ // using this plugin will launch the server in the background and won't block the tests
+ id 'com.github.psxpaul.execfork' version '0.1.8'
+ id 'play'
+}
+
+ext {
+ minJavaVersionForTests = JavaVersion.VERSION_1_8
+ playHttpPort = 8080
+}
+
+def playVersion = "2.6.20"
+def scalaVersion = System.getProperty("scala.binary.version", /* default = */ "2.12")
+
+model {
+ components {
+ play {
+ platform play: playVersion, scala: scalaVersion, java: '1.8'
+ injectedRoutesGenerator = true
+ sources {
+ scala {
+ source.srcDir "src/main/scala"
+ }
+ extraRoutes(RoutesSourceSet) {
+ source.srcDir "src/main/conf"
+ }
+ }
+ }
+ }
+ distributions {
+ playBinary {
+ contents {
+ from("src/main/conf") {
+ into "conf"
+ }
+ }
+ }
+ }
+}
+
+repositories {
+ jcenter()
+ maven {
+ name "lightbend-maven-releases"
+ url "https://repo.lightbend.com/lightbend/maven-release"
+ }
+ ivy {
+ name "lightbend-ivy-release"
+ url "https://repo.lightbend.com/lightbend/ivy-releases"
+ layout "ivy"
+ }
+}
+
+apply from: "${rootDir}/gradle/java.gradle"
+
+description = 'Play Integration Tests.'
+
+dependencies {
+ play "com.typesafe.play:play-guice_$scalaVersion:$playVersion"
+ play "com.typesafe.play:play-logback_$scalaVersion:$playVersion"
+ play "com.typesafe.play:filters-helpers_$scalaVersion:$playVersion"
+
+ play project(':dd-trace-api')
+ play deps.opentracing
+
+ testCompile project(':dd-trace-api')
+ testCompile project(':dd-trace-ot')
+ testCompile project(':dd-java-agent:testing')
+ testCompile group: 'com.squareup.okhttp3', name: 'okhttp', version: '3.6.0'
+}
+
+/** Open up a random, reusable port. */
+def randomOpenPort() {
+ final ServerSocket socket
+ try {
+ socket = new ServerSocket(0)
+ socket.setReuseAddress(true)
+ socket.close()
+ return socket.getLocalPort()
+ } catch (final IOException ioe) {
+ ioe.printStackTrace()
+ return -1
+ }
+}
+
+task unzip(type: Copy) {
+ def zipFile = file("${buildDir}/distributions/playBinary.zip")
+ def outputDir = file("${buildDir}/unpacked/dist")
+
+ from zipTree(zipFile)
+ into outputDir
+
+ dependsOn 'dist'
+}
+
+task startServer(type: com.github.psxpaul.task.ExecFork) {
+ playHttpPort = randomOpenPort()
+
+ if (playHttpPort == -1) {
+ throw new GradleException("Failed to get random port to start Play")
+ }
+
+ workingDir = "${buildDir}/unpacked/dist/playBinary"
+ commandLine = "${workingDir}/bin/playBinary"
+ stopAfter = test
+ // these params tells the ExecFork plugin to block on startServer task until the port is opened or the string is seen in the ouput
+ waitForPort = playHttpPort
+ waitForOutput = "Listening for HTTP on /127.0.0.1:${playHttpPort}"
+ environment = [
+ 'JAVA_OPTS' : "-javaagent:${project(':dd-java-agent').tasks.shadowJar.archivePath}"
+ + " -Ddd.writer.type=LoggingWriter" + " -Ddd.service.name=java-app"
+ + " -Ddatadog.slf4j.simpleLogger.defaultLogLevel=debug"
+ + " -Dorg.slf4j.simpleLogger.defaultLogLevel=debug"
+ + " -Dconfig.file=${workingDir}/conf/application.conf -Dhttp.port=${playHttpPort}"
+ + " -Dhttp.address=127.0.0.1"
+ ]
+
+ dependsOn unzip
+}
+
+task deletePIDFile() {
+ delete "${buildDir}/unpacked/dist/playBinary/RUNNING_PID"
+}
+
+tasks.withType(Test) {
+ // so the test can get this property
+ jvmArgs "-Ddatadog.ittest.server.port=${playHttpPort}"
+
+ testLogging {
+ events "started"
+ }
+
+ dependsOn project(':dd-java-agent').shadowJar, startServer
+}
+
+// clean up the PID file from the server
+tasks.withType(Test).forEach { it.finalizedBy deletePIDFile }

ADD
dd-java-agent-ittests/play-ittests/src/main/conf/application.conf
+# https://www.playframework.com/documentation/latest/Configuration
+play.http.secret.key=datadogbenchmarktest0xCAFEDEAD
+http.port=8080

ADD
dd-java-agent-ittests/play-ittests/src/main/conf/logback.xml
+<!-- https://www.playframework.com/documentation/latest/SettingsLogger -->
+<configuration>
+
+ <conversionRule conversionWord="coloredLevel" converterClass="play.api.libs.logback.ColoredLevel"/>
+
+ <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>%coloredLevel %logger{15} - %message%n%xException{10}</pattern>
+ </encoder>
+ </appender>
+
+ <appender name="ASYNCSTDOUT" class="ch.qos.logback.classic.AsyncAppender">
+ <appender-ref ref="STDOUT"/>
+ </appender>
+
+ <logger name="play" level="INFO"/>
+ <logger name="application" level="DEBUG"/>
+
+ <!-- Off these ones as they are annoying, and anyway we manage configuration ourselves -->
+ <logger name="com.avaje.ebean.config.PropertyMapLoader" level="OFF"/>
+ <logger name="com.avaje.ebeaninternal.server.core.XmlConfigLoader" level="OFF"/>
+ <logger name="com.avaje.ebeaninternal.server.lib.BackgroundThread" level="OFF"/>
+ <logger name="com.gargoylesoftware.htmlunit.javascript" level="OFF"/>
+
+ <root level="WARN">
+ <appender-ref ref="ASYNCSTDOUT"/>
+ </root>
+
+</configuration>

ADD
dd-java-agent-ittests/play-ittests/src/main/conf/routes
+# Routes
+# This file defines all application routes (Higher priority routes first)
+# https://www.playframework.com/documentation/latest/ScalaRouting
+# ~~~~
+
+# An example controller showing a sample home page
+GET /welcome controllers.HomeController.doGet(id: Option[Int])

ADD
dd-java-agent-ittests/play-ittests/src/main/scala/app/controllers/HomeController.scala
+package controllers
+
+import javax.inject.Inject
+
+import play.api.mvc._
+
+/**
+ * This controller creates an `Action` to handle HTTP requests to the
+ * application's welcome greeting
+ */
+class HomeController @Inject()(cc: ControllerComponents) extends AbstractController(cc) {
+
+ /**
+ * Create an Action to return a greeting
+ */
+ def doGet(id: Option[Int]) = Action { implicit request: Request[AnyContent] =>
+ val idVal = id.getOrElse(-1)
+ if (idVal > 0) {
+ Ok("Welcome %d.".format(idVal))
+ } else {
+ Ok("No ID.")
+ }
+ }
+}

ADD
dd-java-agent-ittests/play-ittests/src/test/groovy/datadog/trace/agent/PlaySmokeTest.groovy
+package datadog.trace.agent
+
+import datadog.trace.agent.test.utils.OkHttpUtils
+import okhttp3.OkHttpClient
+import okhttp3.Request
+import spock.lang.Specification
+
+class PlaySmokeTest extends Specification {
+
+ OkHttpClient client = OkHttpUtils.client()
+ private int port = Integer.parseInt(System.getProperty("datadog.ittest.server.port", "8080"))
+
+ def "welcome endpoint #n th time"() {
+ setup:
+ String url = "http://localhost:$port/welcome?id=$n"
+ def request = new Request.Builder().url(url).get().build()
+
+ when:
+ def response = client.newCall(request).execute()
+
+ then:
+ def responseBodyStr = response.body().string()
+ responseBodyStr == "Welcome $n."
+ response.code() == 200
+
+ where:
+ n << (1..200)
+ }
+}

MODIFY
settings.gradle
settings.gradle
@@ -19,6 +19,9 @@ include ':dd-java-agent:testing'
include ':dd-smoke-tests:wildfly'
+include ':dd-java-agent-ittests'
+include ':dd-java-agent-ittests:play-ittests'
+
// instrumentation:
include ':dd-java-agent:instrumentation:akka-http-10.0'
include ':dd-java-agent:instrumentation:apache-httpclient-4'

Add Play Smoke Test with Java Agent

Adding gradle task & test to compile and start a Play server with the agent, hits a welcome endpoint 200 times as a smoke test.