-
Notifications
You must be signed in to change notification settings - Fork 205
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
Add golden test for example Daml ledger export #9732
Changes from 8 commits
937c7d7
226f3e1
4c35dfe
c4a0dbe
cd14a21
06db16c
8679d5f
3f46d8f
1d089d9
0641916
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,14 @@ | ||
# Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
load( | ||
"//bazel_tools/client_server:client_server_build.bzl", | ||
"client_server_build", | ||
) | ||
load( | ||
"//bazel_tools/sh:sh.bzl", | ||
"sh_inline_test", | ||
) | ||
load( | ||
"//bazel_tools:scala.bzl", | ||
"da_scala_binary", | ||
|
@@ -111,3 +119,65 @@ da_scala_test( | |
"@maven//:io_netty_netty_handler", | ||
], | ||
) | ||
|
||
da_scala_binary( | ||
name = "example-export-client", | ||
srcs = ["src/example-export/scala/com/daml/script/export/ExampleClient.scala"], | ||
main_class = "com.daml.script.export.ExampleClient", | ||
scala_deps = [ | ||
"@maven//:com_github_scopt_scopt", | ||
], | ||
deps = [ | ||
":export", | ||
"//daml-lf/data", | ||
"//daml-script/runner:script-runner-lib", | ||
"//language-support/scala/bindings", | ||
"//language-support/scala/bindings-akka", | ||
"//ledger/ledger-api-common", | ||
"//libs-scala/auth-utils", | ||
], | ||
) | ||
|
||
client_server_build( | ||
name = "example-export", | ||
outs = [ | ||
"example-export/Export.daml", | ||
"example-export/args.json", | ||
], | ||
client = ":example-export-client", | ||
client_files = ["//daml-script/test:script-test.dar"], | ||
data = ["//daml-script/test:script-test.dar"], | ||
output_env = "EXPORT_OUT", | ||
server = "//ledger/sandbox:sandbox-binary", | ||
server_files = ["//daml-script/test:script-test.dar"], | ||
) | ||
|
||
# Compare the generated Daml ledger export to the example export used in the | ||
# documentation. This functions as both a golden test on ledger exports and to | ||
# make sure that the documentation stays up-to-date. | ||
sh_inline_test( | ||
name = "example-export-compare", | ||
cmd = """\ | ||
EXPECTED_EXPORT=$$(canonicalize_rlocation $(rootpath //docs:source/tools/export/output-root/Export.daml)) | ||
EXPECTED_ARGS=$$(canonicalize_rlocation $(rootpath //docs:source/tools/export/output-root/args.json)) | ||
ACTUAL_EXPORT=$$(canonicalize_rlocation $(rootpath :example-export/Export.daml)) | ||
ACTUAL_ARGS=$$(canonicalize_rlocation $(rootpath :example-export/args.json)) | ||
# Normalize the expected file by removing the copyright header and any documentation import markers. | ||
# Normalize the actual output by adding a newline to the last line if missing. | ||
Comment on lines
+169
to
+170
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should these comments go on top of the test rule? Spotting comments on inlined scripts can be tricky. Duplicating the comment is probably fine. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's a good point. I've expanded the top comment and kept the comment in the inline code. |
||
$(POSIX_DIFF) -Naur <($(POSIX_SED) '1,3d;/^-- EXPORT/d' $$EXPECTED_EXPORT) <($(POSIX_SED) '$$a\\' $$ACTUAL_EXPORT) || { | ||
echo "$$EXPECTED_EXPORT did not match $$ACTUAL_EXPORT" | ||
exit 1 | ||
} | ||
$(POSIX_DIFF) -Naur $$EXPECTED_ARGS <($(POSIX_SED) '$$a\\' $$ACTUAL_ARGS) || { | ||
echo "$$EXPECTED_ARGS did not match $$ACTUAL_ARGS" | ||
exit 1 | ||
} | ||
""", | ||
data = [ | ||
":example-export/Export.daml", | ||
":example-export/args.json", | ||
"//docs:source/tools/export/output-root/Export.daml", | ||
"//docs:source/tools/export/output-root/args.json", | ||
], | ||
toolchains = ["@rules_sh//sh/posix:make_variables"], | ||
) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
// Copyright (c) 2021 Digital Asset (Switzerland) GmbH and/or its affiliates. All rights reserved. | ||
// SPDX-License-Identifier: Apache-2.0 | ||
|
||
package com.daml.script.export | ||
|
||
import java.io.File | ||
import java.nio.file.{Path, Paths} | ||
import java.time.Duration | ||
|
||
import com.daml.ledger.api.tls.TlsConfiguration | ||
import com.daml.lf.engine.script.{RunnerConfig, RunnerMain} | ||
|
||
case class ExampleClientConfig( | ||
darPath: File, | ||
targetPort: Int, | ||
outputPath: Path, | ||
) | ||
|
||
object ExampleClientConfig { | ||
def parse(args: Array[String]): Option[ExampleClientConfig] = | ||
parser.parse( | ||
args, | ||
ExampleClientConfig( | ||
darPath = null, | ||
targetPort = -1, | ||
outputPath = null, | ||
), | ||
) | ||
|
||
private def parseExportOut( | ||
envVar: String | ||
): Either[String, ExampleClientConfig => ExampleClientConfig] = { | ||
if (envVar.isEmpty) Left("Environment variable EXPORT_OUT must not be empty") | ||
else | ||
envVar.split(" ") match { | ||
case Array(export_daml, args_json) => | ||
val export_daml_path = Paths.get(export_daml) | ||
val args_json_path = Paths.get(args_json) | ||
if (export_daml_path.getParent == null) { | ||
Left("First component in environment variable EXPORT_OUT has no parent") | ||
} else if (export_daml_path.getParent != args_json_path.getParent) { | ||
Left( | ||
"First and second component in environment variable EXPORT_OUT have different parent" | ||
) | ||
} else { | ||
Right(c => c.copy(outputPath = export_daml_path.getParent)) | ||
} | ||
case _ => Left("Environment variable EXPORT_OUT must contain one path") | ||
} | ||
} | ||
|
||
private val parser = new scopt.OptionParser[ExampleClientConfig]("script-export") { | ||
help("help") | ||
.text("Show this help message.") | ||
opt[Int]("target-port") | ||
.required() | ||
.action((x, c) => c.copy(targetPort = x)) | ||
.text("Daml ledger port to connect to.") | ||
opt[String]("output") | ||
.hidden() | ||
.withFallback(() => sys.env.getOrElse("EXPORT_OUT", "")) | ||
.validate(x => parseExportOut(x).map(_ => ())) | ||
.action { (x, c) => | ||
parseExportOut(x) match { | ||
case Left(msg) => | ||
throw new RuntimeException(s"Failed to validate EXPORT_OUT environment variable: $msg") | ||
case Right(f) => f(c) | ||
} | ||
} | ||
arg[File]("dar") | ||
.required() | ||
.action((f, c) => c.copy(darPath = f)) | ||
.text("Path to the dar file containing the initialization script") | ||
} | ||
} | ||
|
||
object ExampleClient { | ||
def main(args: Array[String]): Unit = { | ||
ExampleClientConfig.parse(args) match { | ||
case Some(clientConfig) => main(clientConfig) | ||
case None => sys.exit(1) | ||
} | ||
} | ||
def main(clientConfig: ExampleClientConfig): Unit = { | ||
RunnerMain.main( | ||
RunnerConfig( | ||
darPath = clientConfig.darPath, | ||
scriptIdentifier = "ScriptExample:initializeFixed", | ||
ledgerHost = Some("localhost"), | ||
ledgerPort = Some(clientConfig.targetPort), | ||
participantConfig = None, | ||
timeMode = Some(RunnerConfig.DefaultTimeMode), | ||
commandTtl = Duration.ofSeconds(30L), | ||
inputFile = None, | ||
outputFile = None, | ||
accessTokenFile = None, | ||
tlsConfig = TlsConfiguration(false, None, None, None), | ||
jsonApi = false, | ||
maxInboundMessageSize = RunnerConfig.DefaultMaxInboundMessageSize, | ||
applicationId = None, | ||
) | ||
) | ||
Main.main( | ||
Config.Empty.copy( | ||
ledgerHost = "localhost", | ||
ledgerPort = clientConfig.targetPort, | ||
parties = Seq("Alice", "Bob"), | ||
exportType = Some( | ||
Config.EmptyExportScript.copy( | ||
sdkVersion = "0.0.0", | ||
outputPath = clientConfig.outputPath, | ||
) | ||
), | ||
) | ||
) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. 😃