JSON API perf test main that starts sandbox and json-api services (#7283)

* reintroducing the main

* Introducing `ledger-service/http-json-testing`

* cleaning up

* Starting sandbox and json-api from perf-test main

changelog_begin
changelog_end
This commit is contained in:
Leonid Shlyapnikov 2020-08-31 18:55:01 -04:00 committed by GitHub
parent 1eefb4b27d
commit 20e2922b3e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 299 additions and 6 deletions

View File

@ -3,6 +3,7 @@
load(
"//bazel_tools:scala.bzl",
"da_scala_binary",
"da_scala_library",
"da_scala_test",
"lf_scalacopts",
@ -22,13 +23,70 @@ da_scala_library(
scalacopts = hj_scalacopts,
tags = ["maven_coordinates=com.daml:http-json-perf:__VERSION__"],
visibility = ["//visibility:public"],
runtime_deps = [
"@maven//:ch_qos_logback_logback_classic",
],
deps = [
"//language-support/scala/bindings-akka",
"//ledger-api/rs-grpc-bridge",
"//ledger-service/http-json",
"//ledger-service/http-json-testing",
"//ledger-service/jwt",
"//libs-scala/scala-utils",
"@maven//:com_fasterxml_jackson_core_jackson_core",
"@maven//:com_fasterxml_jackson_core_jackson_databind",
"@maven//:com_github_scopt_scopt_2_12",
"@maven//:com_typesafe_akka_akka_actor_2_12",
"@maven//:com_typesafe_akka_akka_http_core_2_12",
"@maven//:com_typesafe_akka_akka_stream_2_12",
"@maven//:com_typesafe_scala_logging_scala_logging_2_12",
"@maven//:io_gatling_gatling_commons",
"@maven//:io_gatling_gatling_core",
"@maven//:io_gatling_gatling_http",
"@maven//:io_gatling_gatling_http_client",
"@maven//:org_scalaz_scalaz_core_2_12",
"@maven//:org_slf4j_slf4j_api",
],
)
da_scala_binary(
name = "http-json-perf-binary",
data = [
":release/json-api-perf-logback.xml",
],
jvm_flags = [
"-Dlogback.configurationFile=$(location :release/json-api-perf-logback.xml)",
],
main_class = "com.daml.http.perf.Main",
scalacopts = hj_scalacopts,
tags = [
"maven_coordinates=com.daml:http-json-perf-deploy:__VERSION__",
"no_scala_version_suffix",
],
visibility = ["//visibility:public"],
deps = [
":http-json-perf",
"//language-support/scala/bindings-akka",
"//ledger-api/rs-grpc-bridge",
"//ledger-service/http-json",
"//ledger-service/http-json-testing",
"//ledger-service/jwt",
"//libs-scala/scala-utils",
"@maven//:ch_qos_logback_logback_classic",
"@maven//:com_fasterxml_jackson_core_jackson_core",
"@maven//:com_fasterxml_jackson_core_jackson_databind",
"@maven//:com_github_scopt_scopt_2_12",
"@maven//:com_typesafe_akka_akka_actor_2_12",
"@maven//:com_typesafe_akka_akka_http_core_2_12",
"@maven//:com_typesafe_akka_akka_stream_2_12",
"@maven//:com_typesafe_scala_logging_scala_logging_2_12",
"@maven//:io_gatling_gatling_commons",
"@maven//:io_gatling_gatling_core",
"@maven//:io_gatling_gatling_http",
"@maven//:io_gatling_gatling_http_client",
"@maven//:org_scalaz_scalaz_core_2_12",
"@maven//:org_slf4j_slf4j_api",
],
)
exports_files(["release/json-api-perf-logback.xml"])

View File

@ -0,0 +1,17 @@
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="io.netty" level="WARN" />
<logger name="io.grpc.netty" level="WARN" />
<logger name="ch.qos.logback" level="WARN" />
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -0,0 +1,85 @@
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.http.perf
import java.io.File
import com.daml.jwt.JwtDecoder
import com.daml.jwt.domain.Jwt
import scopt.RenderingMode
import scala.concurrent.duration.{Duration, FiniteDuration}
private[perf] final case class Config(
scenario: String,
dars: List[File],
jwt: Jwt,
packageId: Option[String],
maxDuration: Option[FiniteDuration]
) {
override def toString: String =
s"Config(" +
s"scenario=${this.scenario}, " +
s"dars=${dars: List[File]}," +
s"jwt=..., " + // don't print the JWT
s"packageId=${this.packageId: Option[String]}," +
s"maxDuration=${this.maxDuration: Option[FiniteDuration]}" +
")"
}
private[perf] object Config {
val Empty =
Config(scenario = "", dars = List.empty, jwt = Jwt(""), packageId = None, maxDuration = None)
def parseConfig(args: Seq[String]): Option[Config] =
configParser.parse(args, Config.Empty)
@SuppressWarnings(Array("org.wartremover.warts.NonUnitStatements"))
private val configParser: scopt.OptionParser[Config] =
new scopt.OptionParser[Config]("http-json-perf-binary") {
override def renderingMode: RenderingMode = RenderingMode.OneColumn
head("JSON API Perf Test Tool")
help("help").text("Print this usage text")
opt[String]("scenario")
.action((x, c) => c.copy(scenario = x))
.required()
.text("Performance test scenario to run")
opt[Seq[File]]("dars")
.action((x, c) => c.copy(dars = x.toList))
.required()
.text("DAR files to pass to Sandbox")
opt[String]("jwt")
.action((x, c) => c.copy(jwt = Jwt(x)))
.required()
.validate(validateJwt)
.text("JWT token to use when connecting to JSON API")
opt[String]("package-id")
.action((x, c) => c.copy(packageId = Some(x)))
.optional()
.text("Optional package ID to specify in the commands sent to JSON API")
opt[Duration]("max-duration")
.action((x, c) => c.copy(maxDuration = Some(FiniteDuration(x.length, x.unit))))
.optional()
.text(s"Optional maximum perf test duration. Default value infinity. Examples: 500ms, 5s, 10min, 1h, 1d.")
}
private def validateJwt(s: String): Either[String, Unit] = {
import scalaz.syntax.show._
JwtDecoder
.decode(Jwt(s))
.bimap(
error => error.shows,
_ => ()
)
.toEither
}
}

View File

@ -0,0 +1,86 @@
// Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
// SPDX-License-Identifier: Apache-2.0
package com.daml.http.perf
import akka.actor.ActorSystem
import akka.stream.Materializer
import com.daml.grpc.adapter.{AkkaExecutionSequencerPool, ExecutionSequencerFactory}
import com.daml.http.HttpServiceTestFixture.withHttpService
import com.daml.scalautil.Statement.discard
import com.typesafe.scalalogging.StrictLogging
import scala.concurrent.duration.{Duration, _}
import scala.concurrent.{Await, ExecutionContext, Future, TimeoutException}
import scala.util.{Failure, Success}
object Main extends StrictLogging {
type Scenario = Config => Future[Unit]
sealed abstract class ExitCode(val code: Int) extends Product with Serializable
object ExitCode {
case object Ok extends ExitCode(0)
case object InvalidUsage extends ExitCode(100)
case object StartupError extends ExitCode(101)
case object InvalidScenario extends ExitCode(102)
case object TimedOutScenario extends ExitCode(103)
}
def main(args: Array[String]): Unit = {
val name = "http-json-per"
val terminationTimeout: FiniteDuration = 30.seconds
implicit val asys: ActorSystem = ActorSystem(name)
implicit val mat: Materializer = Materializer(asys)
implicit val aesf: ExecutionSequencerFactory =
new AkkaExecutionSequencerPool(poolName = name, terminationTimeout = terminationTimeout)
implicit val ec: ExecutionContext = asys.dispatcher
def terminate(): Unit = discard { Await.result(asys.terminate(), terminationTimeout) }
val exitCode: ExitCode = Config.parseConfig(args) match {
case Some(config) =>
val exitCodeF: Future[ExitCode] = main(config)
exitCodeF.onComplete {
case Success(_) => logger.info(s"Scenario: ${config.scenario: String} completed")
case Failure(e) => logger.error(s"Scenario: ${config.scenario: String} failed", e)
}
try {
Await.result(exitCodeF, config.maxDuration.getOrElse(Duration.Inf))
} catch {
case e: TimeoutException =>
logger.error(s"Scenario: ${config.scenario: String} failed", e)
ExitCode.TimedOutScenario
}
case None =>
// error is printed out by scopt
ExitCode.InvalidUsage
}
terminate()
sys.exit(exitCode.code)
}
private def main(config: Config)(
implicit asys: ActorSystem,
mat: Materializer,
aesf: ExecutionSequencerFactory,
ec: ExecutionContext
): Future[ExitCode] = {
logger.info(s"$config")
if (config.scenario == "commands") {
withHttpService(config.scenario, config.dars, None, None) { (_, _, _, _) =>
runScenarioSync(config, _ => Future.unit) // TODO(Leo): scenario runner goes here
}.map(_ => ExitCode.Ok)
} else {
logger.error(s"Unsupported scenario: ${config.scenario}")
Future.successful(ExitCode.InvalidScenario)
}
}
private def runScenarioSync(config: Config, scenario: Scenario)(
implicit ec: ExecutionContext): Future[Unit] = {
scenario(config).map(_ => Thread.sleep(5000)) // XXX
}
}

View File

@ -0,0 +1,52 @@
# Copyright (c) 2020 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
load(
"//bazel_tools:scala.bzl",
"da_scala_library",
"da_scala_test",
"lf_scalacopts",
)
hj_scalacopts = lf_scalacopts + [
"-P:wartremover:traverser:org.wartremover.warts.NonUnitStatements",
]
da_scala_library(
name = "http-json-testing",
srcs = glob(["src/main/scala/**/*.scala"]),
plugins = [
"@maven//:org_spire_math_kind_projector_2_12",
],
scalacopts = hj_scalacopts,
tags = ["maven_coordinates=com.daml:http-json-testing:__VERSION__"],
visibility = ["//visibility:public"],
runtime_deps = [
"@maven//:ch_qos_logback_logback_classic",
],
deps = [
"//bazel_tools/runfiles:scala_runfiles",
"//language-support/scala/bindings-akka",
"//ledger-api/rs-grpc-bridge",
"//ledger-service/http-json",
"//ledger-service/jwt",
"//ledger-service/utils",
"//ledger/caching",
"//ledger/ledger-api-auth",
"//ledger/ledger-api-common",
"//ledger/participant-integration-api",
"//ledger/participant-state",
"//ledger/sandbox-classic",
"//ledger/sandbox-common",
"//libs-scala/auth-utils",
"//libs-scala/ports",
"@maven//:com_typesafe_akka_akka_actor_2_12",
"@maven//:com_typesafe_akka_akka_http_core_2_12",
"@maven//:com_typesafe_akka_akka_stream_2_12",
"@maven//:org_tpolecat_doobie_core_2_12",
"@maven//:org_tpolecat_doobie_free_2_12",
"@maven//:org_typelevel_cats_core_2_12",
"@maven//:org_typelevel_cats_effect_2_12",
"@maven//:org_typelevel_cats_free_2_12",
],
)

View File

@ -175,20 +175,15 @@ da_scala_test(
"//language-support/scala/bindings-akka",
"//ledger-api/rs-grpc-bridge",
"//ledger-service/db-backend",
"//ledger-service/http-json-testing",
"//ledger-service/jwt",
"//ledger-service/utils",
"//ledger/caching",
"//ledger/ledger-api-auth",
"//ledger/ledger-api-common",
"//ledger/participant-integration-api",
"//ledger/participant-state",
"//ledger/sandbox-classic",
"//ledger/sandbox-common",
"//libs-scala/auth-utils",
"//libs-scala/ports",
"//libs-scala/postgresql-testing",
"//libs-scala/scala-utils",
"@maven//:ch_qos_logback_logback_classic",
"@maven//:com_chuusai_shapeless_2_12",
"@maven//:com_github_ghik_silencer_lib_2_12_11",
"@maven//:com_lihaoyi_sourcecode_2_12",