Skip to content

Commit

Permalink
Switch compat tests over to sandbox on x (digital-asset#12716)
Browse files Browse the repository at this point in the history
* Switch compat tests over to sandbox on x

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end

* .

changelog_begin
changelog_end
  • Loading branch information
cocreature authored Feb 3, 2022
1 parent aa45f48 commit 97db5ac
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 63 deletions.
14 changes: 11 additions & 3 deletions compatibility/bazel_tools/create-daml-app/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// `daml start` which is what users use.

import child_process from "child_process";
import { ChildProcess, spawn, SpawnOptions } from "child_process";
import { ChildProcess, execFileSync, spawn, SpawnOptions } from "child_process";
import { promises as fs } from "fs";
import puppeteer, { Browser, Page } from "puppeteer";
import waitOn from "wait-on";
Expand Down Expand Up @@ -127,14 +127,21 @@ beforeAll(async () => {
await removeFile(`../${SANDBOX_PORT_FILE_NAME}`);
await removeFile(`../${JSON_API_PORT_FILE_NAME}`);

const sandboxOptions = [
(process.env.SANDBOX_VERSION[0] == "1") ? "sandbox" : "sandbox-kv",
const kvSandboxOptions = [
"sandbox",
`--ledgerid=${SANDBOX_LEDGER_ID}`,
`--port=0`,
`--port-file=${SANDBOX_PORT_FILE_NAME}`,
DAR_PATH,
];


const sandboxOnXOptions = [
`--ledger-id=${SANDBOX_LEDGER_ID}`,
`--participant=participant-id=sandbox,port=0,port-file=${SANDBOX_PORT_FILE_NAME}`
];
const sandboxOptions = process.env.SANDBOX_VERSION[0] == "1" ? kvSandboxOptions : sandboxOnXOptions;

sandbox = spawn(process.env.DAML_SANDBOX, sandboxOptions, {
cwd: "..",
stdio: "inherit",
Expand All @@ -146,6 +153,7 @@ beforeAll(async () => {
const sandboxPort = parseInt(
await fs.readFile(SANDBOX_PORT_FILE_PATH, "utf8")
);
execFileSync(process.env.DAML, ["ledger", "upload-dar", "--host=localhost", `--port=${sandboxPort}`, DAR_PATH])

const jsonApiOptions = [
"json-api",
Expand Down
2 changes: 1 addition & 1 deletion compatibility/bazel_tools/create_daml_app_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ canonicalize_rlocation() {
}

RUNNER="$(rlocation "$TEST_WORKSPACE/$1")"
DAML="$(rlocation "$TEST_WORKSPACE/$2")"
export DAML="$(rlocation "$TEST_WORKSPACE/$2")"
# These things are only used in the jest tests so rather
# than adding a lot of boilerplate to the Haskell code
# to parse them only to pass them on, we simply set them here.
Expand Down
59 changes: 33 additions & 26 deletions compatibility/bazel_tools/daml_ledger/Main.hs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,23 @@
module Main (main) where

import Control.Applicative
import Control.Exception
import DA.Test.Process
import Data.Either.Extra
import Data.Function ((&))
import Data.List.Extra (replace)
import Data.Maybe (fromMaybe)
import Data.Proxy (Proxy (..))
import Data.SemVer (Version)
import qualified Data.SemVer as SemVer
import Data.Tagged (Tagged (..))
import Sandbox (maxRetries, nullDevice, readPortFile)
import System.Directory.Extra (withCurrentDirectory)
import System.Environment (lookupEnv)
import System.Environment.Blank (setEnv)
import System.FilePath ((</>), takeBaseName)
import System.IO.Extra (withTempDir,writeFileUTF8)
import System.IO.Extra (IOMode(ReadWriteMode), hClose, newTempDir, openBinaryFile, withTempDir, writeFileUTF8)
import System.Process
import Test.Tasty (TestTree,askOption,defaultMainWithIngredients,defaultIngredients,includingOptions,testGroup,withResource)
import Test.Tasty.Options (IsOption(..), OptionDescription(..), mkOptionCLParser)
import Test.Tasty.HUnit
Expand All @@ -27,13 +31,33 @@ import qualified Data.Map as Map
import qualified Data.Text as T
import qualified Web.JWT as JWT

import Sandbox

data Tools = Tools
{ daml :: FilePath
, sandboxConfig :: SandboxConfig
, sandboxBinary :: FilePath
, sandboxArgs :: [String]
}

withSandbox :: IO Tools -> Maybe String -> (IO Int -> TestTree) -> TestTree
withSandbox getTools mbSecret f =
withResource (openBinaryFile nullDevice ReadWriteMode) hClose $ \getDevNull ->
withResource newTempDir snd $ \getTempDir ->
let createSandbox = do
Tools{..} <- getTools
(tmpDir, _) <- getTempDir
let portFile = tmpDir </> "portfile"
devNull <- getDevNull
let args = map (tweakArg portFile) (sandboxArgs <> ["--auth-jwt-hs256-unsafe=" <> secret | Just secret <- [mbSecret]])
mask $ \unmask -> do
ph <- createProcess (proc sandboxBinary args) { std_out = UseHandle devNull }
let waitForStart = do
port <- readPortFile maxRetries portFile
pure (port, ph)
unmask (waitForStart `onException` cleanupProcess ph)
destroySandbox = cleanupProcess . snd
in withResource createSandbox destroySandbox (f . fmap fst)
where
tweakArg portFile = replace "__PORTFILE__" portFile

newtype DamlOption = DamlOption FilePath
instance IsOption DamlOption where
defaultValue = DamlOption "daml"
Expand All @@ -55,21 +79,13 @@ instance IsOption SandboxArgsOption where
optionName = Tagged "sandbox-arg"
optionHelp = Tagged "extra arguments to pass to sandbox executable"
optionCLParser = concatMany (mkOptionCLParser mempty)
where concatMany = fmap (SandboxArgsOption . concat) . many . fmap unSandboxArgsOption

newtype CertificatesOption = CertificatesOption FilePath
instance IsOption CertificatesOption where
defaultValue = CertificatesOption "certificates"
parseValue = Just . CertificatesOption
optionName = Tagged "certs"
optionHelp = Tagged "runfiles path to the certificates directory"
where concatMany = fmap (SandboxArgsOption . concat) . some . fmap unSandboxArgsOption

withTools :: (IO Tools -> TestTree) -> TestTree
withTools tests = do
askOption $ \(DamlOption damlPath) -> do
askOption $ \(SandboxOption sandboxPath) -> do
askOption $ \(SandboxArgsOption sandboxArgs) -> do
askOption $ \(CertificatesOption certificatesPath) -> do
let createRunfiles :: IO (FilePath -> FilePath)
createRunfiles = do
runfiles <- Bazel.Runfiles.create
Expand All @@ -79,15 +95,10 @@ withTools tests = do
let tools = do
daml <- locateRunfiles <*> pure damlPath
sandboxBinary <- locateRunfiles <*> pure sandboxPath
sandboxCertificates <- locateRunfiles <*> pure certificatesPath
let sandboxConfig = defaultSandboxConf
{ sandboxBinary
, sandboxArgs
, sandboxCertificates
}
pure Tools
{ daml
, sandboxConfig
, sandboxBinary
, sandboxArgs
}
tests tools

Expand Down Expand Up @@ -118,7 +129,6 @@ main = do
[ Option @DamlOption Proxy
, Option @SandboxOption Proxy
, Option @SandboxArgsOption Proxy
, Option @CertificatesOption Proxy
, Option @SdkVersion Proxy
]
let ingredients = defaultIngredients ++ [includingOptions options]
Expand All @@ -133,7 +143,7 @@ main = do
-- | Test `daml ledger list-parties --access-token-file`
authenticatedUploadTest :: SdkVersion -> IO Tools -> TestTree
authenticatedUploadTest sdkVersion getTools = do
withSandbox getSandboxConfig $ \getSandboxPort -> testGroup "authentication" $
withSandbox getTools (Just sharedSecret) $ \getSandboxPort -> testGroup "authentication" $
[ testCase "Bearer prefix" $ do
Tools{..} <- getTools
port <- getSandboxPort
Expand Down Expand Up @@ -165,9 +175,6 @@ authenticatedUploadTest sdkVersion getTools = do
]
where
sharedSecret = "TheSharedSecret"
getSandboxConfig = do
cfg <- sandboxConfig <$> getTools
pure cfg { mbSharedSecret = Just sharedSecret }

makeSignedJwt :: String -> String
makeSignedJwt sharedSecret = do
Expand All @@ -179,7 +186,7 @@ makeSignedJwt sharedSecret = do

unauthenticatedTests :: SdkVersion -> IO Tools -> TestTree
unauthenticatedTests sdkVersion getTools = do
withSandbox (sandboxConfig <$> getTools) $ \getSandboxPort ->
withSandbox getTools Nothing $ \getSandboxPort ->
testGroup "unauthenticated"
[ fetchTest sdkVersion getTools getSandboxPort
]
Expand Down
15 changes: 5 additions & 10 deletions compatibility/bazel_tools/daml_ledger_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# SPDX-License-Identifier: Apache-2.0

# Copy-pasted from the Bazel Bash runfiles library v2.
$@
set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
Expand All @@ -14,14 +15,8 @@ source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
set -euo pipefail

RUNNER="$(rlocation "$TEST_WORKSPACE/$1")"
SDK_VERSION="$2"
DAML="$(rlocation "$TEST_WORKSPACE/$3")"
CERTS="$4"
SANDBOX="$(rlocation "$TEST_WORKSPACE/$5")"

"$RUNNER" \
--sdk-version "$SDK_VERSION" \
--daml "$DAML" \
--certs "$CERTS" \
--sandbox "$SANDBOX" \
"${@:6}"
DAML="$(rlocation "$TEST_WORKSPACE/$2")"
SANDBOX="$(rlocation "$TEST_WORKSPACE/$3")"

$RUNNER --daml $DAML --sandbox $SANDBOX ${@:4}
11 changes: 8 additions & 3 deletions compatibility/bazel_tools/daml_sdk.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,11 @@ $(rlocation daml-sdk-{version}/sdk/bin/daml) $@
Label("@compatibility//bazel_tools:daml.cc.tpl"),
substitutions = {"{SDK_VERSION}": ctx.attr.version},
)
ctx.template(
"sandbox-on-x.cc",
Label("@compatibility//bazel_tools:run_jar.cc.tpl"),
substitutions = {"{SDK_VERSION}": ctx.attr.version, "{JAR_NAME}": "sandbox-on-x.jar"},
)
ctx.file(
"BUILD",
content =
Expand All @@ -169,11 +174,11 @@ sh_binary(
data = [":ledger-api-test-tool.jar"],
deps = ["@bazel_tools//tools/bash/runfiles"],
)
sh_binary(
cc_binary(
name = "sandbox-on-x",
srcs = [":sandbox-on-x.sh"],
srcs = ["sandbox-on-x.cc"],
data = [":sandbox-on-x.jar"],
deps = ["@bazel_tools//tools/bash/runfiles"],
deps = ["@bazel_tools//tools/cpp/runfiles:runfiles"],
)
cc_binary(
name = "daml",
Expand Down
100 changes: 100 additions & 0 deletions compatibility/bazel_tools/run_jar.cc.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
#include "tools/cpp/runfiles/runfiles.h"
#include <codecvt>
#include <iostream>
#include <locale>
#include <memory>
#include <unistd.h>
#include <cstring>
#if defined(_WIN32)
#include <windows.h>
#endif

using bazel::tools::cpp::runfiles::Runfiles;

/*
NOTE (MK): Why is this not just an sh_binary?
Good question! It turns out that on Windows, an
sh_binary creates a custom executable that then launches
bash. Somehow this seems to result in a double fork
(or the Windows-equivalent) thereof which results in
child processes not being childs of the original process.
This makes it really hard to kill a process including
all child processes which is really important since
otherwise you are left with a running JVM process
if you kill `daml sandbox`.
*/

int main(int argc, char **argv) {
std::string error;
std::unique_ptr<Runfiles> runfiles(Runfiles::Create(argv[0], &error));
if (runfiles == nullptr) {
std::cerr << "Failed to initialize runfiles: " << error << "\n";
exit(1);
}
const char *java_home = getenv("JAVA_HOME");
std::string java = "";
// NOTE (MK) I don’t entirely understand when Bazel defines
// JAVA_HOME and when it doesn’t but it looks like it defines
// it in tests but not in genrules which is good enough for us.
if (java_home) {
#if defined(_WIN32)
java = std::string(java_home) + "/bin/java.exe";
#else
java = std::string(java_home) + "/bin/java";
#endif
}
std::string path =
runfiles->Rlocation("daml-sdk-{SDK_VERSION}/{JAR_NAME}");
#if defined(_WIN32)
// To keep things as simple as possible, we simply take
// the existing command line, strip everything up to the first space
// and replace it. This is obviously not correct if there are spaces
// in the path name but Bazel doesn’t like that either so
// it should be good enough™.
LPWSTR oldCmdLine = GetCommandLineW();
wchar_t *index = wcschr(oldCmdLine, ' ');
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
std::wstring cmdLine = converter.from_bytes(java.c_str());
cmdLine += L" -jar ";
cmdLine += converter.from_bytes(path.c_str());
if (index) {
cmdLine += std::wstring(index);
}
const int MAX_CMDLINE_LENGTH = 32768;
wchar_t result[MAX_CMDLINE_LENGTH];
wcsncpy(result, cmdLine.c_str(), MAX_CMDLINE_LENGTH - 1);
result[MAX_CMDLINE_LENGTH - 1] = 0;
PROCESS_INFORMATION processInfo = {0};
STARTUPINFOW startupInfo = {0};
startupInfo.cb = sizeof(startupInfo);
BOOL ok = CreateProcessW(NULL, result, NULL, NULL, TRUE, 0, NULL, NULL,
&startupInfo, &processInfo);
if (!ok) {
std::wcerr << "Cannot launch process: " << cmdLine << "\n";
return GetLastError();
}
WaitForSingleObject(processInfo.hProcess, INFINITE);
DWORD exit_code;
GetExitCodeProcess(processInfo.hProcess, &exit_code);
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
return exit_code;

#else
char**const argv_ = (char**)malloc((argc + 2) * sizeof(char*));
char* javaStr = new char[java.length() + 1];
std::strcpy(javaStr, java.c_str());
argv_[0] = javaStr;
char* jarStr = new char[strlen("-jar") + 1];
std::strcpy(jarStr, "-jar");
argv_[1] = jarStr;
char* pathStr = new char[path.length() + 1];
std::strcpy(pathStr, path.c_str());
argv_[2] = pathStr;
for (int i = 1; i < argc; i++) {
argv_[i + 2] = argv[i];
}
argv_[argc + 2] = NULL;
execvp(java.c_str(), argv_);
#endif
}
Loading

0 comments on commit 97db5ac

Please sign in to comment.