Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@

# Entries below this point are managed by Please (DO NOT EDIT)
plz-out
.plzconfig.local
18 changes: 18 additions & 0 deletions .plzconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[PluginDefinition]
Name = e2e

[PluginConfig "please_tool"]
DefaultValue = //tools:please
Inherit = true

[PluginConfig "please_version"]
DefaultValue = latest
Inherit = true

[PluginConfig "base_config"]
DefaultValue = //data:base_config

[PluginConfig "content_checker"]
DefaultValue = //tools:content_checker

[Plugin "e2e"]
Empty file added BUILD
Empty file.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
# plugin-integration-testing
Build definitions for integration testing Please plugins

# plz_e2e_test
A light weight test that runs Please in the current repo. It has a number of arguments that you can use to test various
conditions around the output of the command.

# please_repo_e2e_test
Similar to `plz_e2e_test` however it runs Please in the test repo passed in via the `repo` argument. Use `BUILD_FILE`
instead of `BUILD` as the build file name in the test repo to avoid collisions with the main Please repo.
6 changes: 6 additions & 0 deletions build_defs/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
filegroup(
name = "e2e",
srcs = ["e2e.build_defs"],
visibility = ["PUBLIC"],
)

134 changes: 134 additions & 0 deletions build_defs/e2e.build_defs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
def please_tool(name:str, version=CONFIG.E2E.PLEASE_VERSION, visibility:list):

version_dep = None
if version == "latest":
version_dep = tag(name, "version")
remote_file(
name = version_dep,
url = "https://get.please.build/latest_version",
visibility = ["PUBLIC"],
)
version = f"$(cat $(location :{version_dep}))"

genrule(
name = name,
cmd = f"export VERSION={version} && curl https://get.please.build/{CONFIG.OS}_{CONFIG.ARCH}/$VERSION/please_$VERSION --output $OUT",
outs = [name],
visibility = visibility,
deps = [f":{version_dep}"] if version_dep else None,
binary = True,
)

# Runs e2e tests against please in a specified repo
def please_repo_e2e_test(
name: str,
plz_command: str,
repo: str,
data: dict={},
deps: list=[],
tools: dict={},
expected_failure: bool = False,
expected_output: dict = {},
expect_output_contains: dict = {},
expect_output_doesnt_contain: dict = {},
labels: list = [],
):
plz_command = plz_command.replace("plz ", "$TOOLS_PLEASE ")
if expected_failure:
plz_command += "; [ ! $? -eq 0 ]"

test_cmd = [
"mv $DATA_BASE_CONFIG $DATA_REPO",
"cd $DATA_REPO",
plz_command,
]

if expected_output:
test_cmd += [f"$TOOLS_CONTENT_CHECKER '{o}' '{c}'" for o, c in expected_output.items()]

if expect_output_contains:
test_cmd += [f'_STR="$(cat {o})" _SUBSTR="{c}" && if [ "${_STR##*$_SUBSTR*}" ]; then echo "$_STR"; exit 1; fi' for o, c in expect_output_contains.items()]

if expect_output_doesnt_contain:
test_cmd += [f'_STR="$(cat {o})" _SUBSTR="{c}" && if [ -z "${_STR##*$_SUBSTR*}" ]; then echo "$_STR"; exit 1; fi' for o, c in expect_output_contains.items()]

test_cmd = ' && '.join(test_cmd)

data["REPO"] = [repo]
data["BASE_CONFIG"] = [CONFIG.E2E.BASE_CONFIG]

tools["PLEASE"] = [CONFIG.E2E.PLEASE_TOOL]
tools["CONTENT_CHECKER"] = [CONFIG.E2E.CONTENT_CHECKER]

return gentest(
name = name,
test_cmd = test_cmd,
test_tools = tools,
data = data,
deps = deps,
env = {
"PLZ_CONFIG_PROFILE": "e2e",
},
no_test_output = True,
labels = labels + ["plz_e2e_test", "e2e"],
sandbox = False,
)

# Like please_repo_e2e_test, this runs end-to-end tests on Please itself but in the current please repo.
def plz_e2e_test(name:str, cmd:str, pre_cmd:str=None, expected_output:str=None,
expected_failure:bool=False, expect_output_contains:str=None,
expect_output_doesnt_contain:str=None, deps:list=None, data:list=[],
labels:list=None, completion:bool=False,
expect_file_exists:str=None, expect_file_doesnt_exist:str=None, timeout:int=None):
# Please isn't really designed to work this way (running a test against the entire source repo)
# but we can make it do it and it's a convenient way of testing the tool itself.

def _e2e_test_cmd(cmd):
args = '$PLZ_ARGS -o sandbox.test:false -o sandbox.build:false -o sandbox.namespace:false '
if package_name().startswith('test/parse'):
args += ' -o parse.buildfilename:BUILD,BUILD.plz,BUILD.test '
cmd = cmd.replace('plz ', f'$TOOLS {args} -o cache.dirclean:false --log_file plz-out/log/{name}.log ')
if expected_failure:
test_cmd = '%s 2>&1 | tee output; if [ $? -eq 0 ]; then exit 1; fi; ' % cmd
else:
test_cmd = '%s 2>&1 | tee output && ' % cmd
if expected_output and expect_output_contains:
raise ValueError('Can only pass one of expected_output and expect_output_contains')
elif expected_output:
test_cmd += 'diff -au output $(location %s)' % expected_output
elif expect_output_contains:
test_cmd += f'_STR="$(cat output)" _SUBSTR="{expect_output_contains}" && if [ "${_STR##*$_SUBSTR*}" ]; then echo "$_STR"; exit 1; fi'
elif expect_output_doesnt_contain:
test_cmd += f'_STR="$(cat output)" _SUBSTR="{expect_output_doesnt_contain}" && if [ -z "${_STR##*$_SUBSTR*}" ]; then echo "$_STR"; exit 1; fi'
elif expect_file_exists:
test_cmd += 'if [ ! -f %s ]; then cat output; exit 1; fi' % expect_file_exists
elif expect_file_doesnt_exist:
test_cmd += 'if [ -f %s ]; then cat output; exit 1; fi' % expect_file_doesnt_exist
else:
test_cmd += 'true'
if completion:
test_cmd = "export GO_FLAGS_COMPLETION=1; " + test_cmd
if pre_cmd:
test_cmd = pre_cmd + ' && ' + test_cmd
return test_cmd

if expected_output:
data += [expected_output]
gentest(
name = name,
test_cmd = {
'opt': _e2e_test_cmd(cmd),
'dbg': _e2e_test_cmd(cmd.replace('plz ', 'plz -c dbg ')),
'cover': _e2e_test_cmd(cmd.replace('plz ', 'plz -c cover ')),
},
data = data,
deps = deps,
test_tools = [CONFIG.E2E.PLEASE_TOOL],
labels = ['e2e'] + (labels or []),
no_test_output = True,
sandbox = False,
local = True,
pass_env = ["PLZ_ARGS"],
exit_on_error = False,
timeout = timeout,
)
3 changes: 3 additions & 0 deletions data/.plzconfig.e2e
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
; Set this so we don't pick up the test BUILD files in the main repo
[parse]
BuildFileName = BUILD_FILE
7 changes: 7 additions & 0 deletions data/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
filegroup(
name = "base_config",
srcs = [
".plzconfig.e2e",
],
visibility = ["PUBLIC"],
)
99 changes: 99 additions & 0 deletions pleasew
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
#!/usr/bin/env bash
set -u

RED="\x1B[31m"
GREEN="\x1B[32m"
YELLOW="\x1B[33m"
RESET="\x1B[0m"

DEFAULT_URL_BASE="https://get.please.build"

OS="$(uname)"

if [[ $OS == "Darwin" ]]; then
# switch between mac amd64/arm64
ARCH="$(uname -m)"
else
# default to amd64 on other operating systems
# because we only build intel binaries
ARCH="amd64"
fi

# Check PLZ_CONFIG_PROFILE or fall back to arguments for a profile.
PROFILE="${PLZ_CONFIG_PROFILE:-$(sed -E 's/.*--profile[= ]([^ ]+).*/\1/g' <<< "$*")}"

# Config files on order of precedence high to low.
CONFIGS=(
".plzconfig.local"
"${PROFILE:+.plzconfig.$PROFILE}"
".plzconfig_${OS}_${ARCH}"
".plzconfig"
"$HOME/.config/please/plzconfig"
"/etc/please/plzconfig"
)

function read_config() {
grep -i "$1" "${CONFIGS[@]}" 2>/dev/null | head -n 1
}

# We might already have it downloaded...
LOCATION="$(read_config "^location" | cut -d '=' -f 2 | tr -d ' ')"
if [ -z "$LOCATION" ]; then
if [ -z "$HOME" ]; then
echo -e >&2 "${RED}\$HOME not set, not sure where to look for Please.${RESET}"
exit 1
fi
LOCATION="${HOME}/.please"
else
# It can contain a literal ~, need to explicitly handle that.
LOCATION="${LOCATION/\~/$HOME}"
fi
# If this exists at any version, let it handle any update.
TARGET="${LOCATION}/please"
if [ -f "$TARGET" ]; then
exec "$TARGET" ${PLZ_ARGS:-} "$@"
fi

URL_BASE="$(read_config "^downloadlocation" | cut -d '=' -f 2 | tr -d ' ')"
if [ -z "$URL_BASE" ]; then
URL_BASE=$DEFAULT_URL_BASE
fi
URL_BASE="${URL_BASE%/}"

VERSION="$(read_config "^version[^a-z]")"
VERSION="${VERSION#*=}" # Strip until after first =
VERSION="${VERSION/ /}" # Remove all spaces
VERSION="${VERSION#>=}" # Strip any initial >=
if [ -z "$VERSION" ]; then
echo -e >&2 "${YELLOW}Can't determine version, will use latest.${RESET}"
VERSION=$(curl -fsSL ${URL_BASE}/latest_version)
fi

# Find the os / arch to download. You can do this quite nicely with go env
# but we use this script on machines that don't necessarily have Go itself.
if [ "$OS" = "Linux" ]; then
GOOS="linux"
elif [ "$OS" = "Darwin" ]; then
GOOS="darwin"
elif [ "$OS" = "FreeBSD" ]; then
GOOS="freebsd"
else
echo -e >&2 "${RED}Unknown operating system $OS${RESET}"
exit 1
fi

PLEASE_URL="${URL_BASE}/${GOOS}_${ARCH}/${VERSION}/please_${VERSION}.tar.xz"
DIR="${LOCATION}/${VERSION}"
# Potentially we could reuse this but it's easier not to really.
if [ ! -d "$DIR" ]; then
rm -rf "$DIR"
fi
echo -e >&2 "${GREEN}Downloading Please ${VERSION} to ${DIR}...${RESET}"
mkdir -p "$DIR"
curl -fsSL "${PLEASE_URL}" | tar -xJpf- --strip-components=1 -C "$DIR"
# Link it all back up a dir
for x in $(ls "$DIR"); do
ln -sf "${DIR}/${x}" "$LOCATION"
done
echo -e >&2 "${GREEN}Should be good to go now, running plz...${RESET}"
exec "$TARGET" ${PLZ_ARGS:-} "$@"
13 changes: 13 additions & 0 deletions tools/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
subinclude("//build_defs:e2e")

please_tool(
name = "please",
visibility = ["PUBLIC"],
)

sh_binary(
name = "content_checker",
main = "test_file_content.sh",
visibility = ["PUBLIC"],
)

14 changes: 14 additions & 0 deletions tools/test_file_content.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/sh

if ! test -f "$1"; then
echo "$1" doesnt exist
exit 1
fi

CONTENT=$(cat "$1")

if [ "$CONTENT" != "$2" ]; then
echo "$1" doesnt contain "$2", it contains "$CONTENT"
exit 1
fi