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
43 changes: 38 additions & 5 deletions bash/daml-export
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,24 @@ function exportRange {
[ -n "$DAML_TOKEN" ] && args+=(--access-token-file "$DAML_TOKEN")
java "${args[@]}"
local export_exit=$?
if [ $export_exit -eq 0 ]; then
touch "$dir/export.good"
else
if [ $export_exit -ne 0 ]; then
# SUR-3644: surface the Java export failure to the caller so the main
# loop skips correction/build instead of reporting false success.
echo "REDO $dir"
return "$export_exit"
fi
# SUR-3644: Java reported success, but the build step depends on the
# exported sources existing. Treat missing artifacts as a failed export
# rather than touching export.good and proceeding on partial output.
local missing=()
[ -r "$dir/daml.yaml" ] || missing+=("daml.yaml")
[ -r "$dir/Export.daml" ] || missing+=("Export.daml")
if [ "${#missing[@]}" -gt 0 ]; then
echo "REDO $dir"
log::error "daml-export: export of $dir is missing required files: ${missing[*]}"
return 1
fi
touch "$dir/export.good"
sleep 1
else
echo "Skipping complete export from $start to $stop"
Expand Down Expand Up @@ -183,6 +196,9 @@ CUR_INT=$(hex_to_dec "$START_OFFSET")
STOP_INT=$(hex_to_dec "$STOP_OFFSET")

count=0
# SUR-3644: track whether any range failed to export so the script can exit
# non-zero overall instead of masking the failure behind a clean build wait.
EXPORT_FAILED=false
RUNNING_PROCS=()
RUNNING_OUTPUT_DIRS=()
# TO_BUILD removed (SUR-1871): the previous queue accumulated every
Expand Down Expand Up @@ -277,12 +293,23 @@ while [ "$CUR_INT" -le "$STOP_INT" ]; do

verifyExport "$OUTPUT_DIR"
if [ $? -ge 2 ]; then
exportRange "$CUR_HEX" "$NEXT_HEX" "$OUTPUT_DIR" "$BASE_DIR"
# SUR-3644: gate correction/build on a successful export. A failed export
# (Java error or missing artifacts) must not be corrected/built.
if exportRange "$CUR_HEX" "$NEXT_HEX" "$OUTPUT_DIR" "$BASE_DIR"; then
export_ok=true
else
export_ok=false
fi
else
export_ok=true
fi

refresh_running_procs

if [ "${#RUNNING_PROCS[@]}" -lt "$MAX_PARALLEL" ]; then
if [ "$export_ok" != true ]; then
log::error "daml-export: skipping correction/build for $OUTPUT_DIR after failed export"
EXPORT_FAILED=true
elif [ "${#RUNNING_PROCS[@]}" -lt "$MAX_PARALLEL" ]; then
correct_export "$OUTPUT_DIR"
build "$OUTPUT_DIR" &
RUNNING_PROCS+=($!)
Expand Down Expand Up @@ -335,6 +362,12 @@ done < <(find "$TARGET_DIR" -name export.good -print | sort)
wait_for_running_procs
WAIT_STATUS=$?
NORMAL_COMPLETION=true
# SUR-3644: a failed export earlier in the run must not be masked by a clean
# build wait — fail loudly so CI/automation does not proceed on missing or
# partial artifacts.
if [ "$EXPORT_FAILED" = true ]; then
exit 1
fi
if [ "$WAIT_STATUS" -ne 0 ]; then
exit "$WAIT_STATUS"
fi
2 changes: 2 additions & 0 deletions bash/minikube-test-environment
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ function start_or_create_minikube {
--kubernetes-version "$KUBERNETES_VERSION" \
--driver="$MINIKUBE_DRIVER" \
--force-systemd=true \
"--cni=$CNI" \
"--nodes=$NODES" \
"--memory=$NODE_MEMORY"
fi
Expand All @@ -68,6 +69,7 @@ function start_or_create_minikube {
--kubernetes-version "$KUBERNETES_VERSION" \
--driver="$MINIKUBE_DRIVER" \
--force-systemd=true \
"--cni=$CNI" \
"--nodes=$NODES" \
"--memory=$NODE_MEMORY"
fi
Expand Down
23 changes: 23 additions & 0 deletions bash/replace-validator
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,26 @@ function waitForPodTermination() {
done
}

# Pre-flight check that every requested node has a pod in the populated
# map. Emits a clear error naming the missing node and selector and returns
# non-zero so `main` can bail out BEFORE any key copy or label mutation,
# rather than aborting on an opaque `nounset` error when dereferencing a
# missing associative-array element. The map is passed by nameref. (SUR-3649)
function validateNodesMapped() {
local -n _map=${1:?}
local label=${2:?}
shift 2
local node
local rc=0
for node in "$@"; do
if [ -z "${_map[$node]+set}" ]; then
log::error "replace-validator: no pod found for node '$node' with selector '$label'"
rc=1
fi
done
return "$rc"
}

function main() {
set -euo pipefail
local -A node2pod=()
Expand All @@ -128,6 +148,9 @@ function main() {
local -A pod2node=()
# shellcheck disable=SC2153
mapPods "$LABEL" node2pod pod2node
# SUR-3649: fail cleanly before any destructive action when a requested
# node has no matching pod, instead of crashing on nounset below.
validateNodesMapped node2pod "$LABEL" "$FROM_NODE" "$TRGT_NODE"
local from_pod=${node2pod[$FROM_NODE]}
local to_pod=${node2pod[$TRGT_NODE]}

Expand Down
38 changes: 38 additions & 0 deletions tests/daml-export.bats
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,44 @@ EOF
rm -f "$log_file"
}

@test "daml-export exits non-zero and skips correction/build when java export fails (SUR-3644)" {
tmp=$(mktemp -d)
stub_bin=$(mktemp -d)
log_file=$(mktemp)
write_daml_stub "$stub_bin"
printf '%s\n' '#!/usr/bin/env bash' 'exit 1' >"$stub_bin/java"
chmod +x "$stub_bin/java"

run env PATH="$stub_bin:$PATH" DAML_STUB_LOG="$log_file" DAML_EXPORT_SOURCE_ONLY= \
bash "$DAML_EXPORT" -d "$tmp" -b 0 -e 1 -s 1 -P 5
[ "$status" -ne 0 ]
[[ "$output" == *"REDO"* ]]
# correct_export must not run on a failed export.
[[ "$output" != *"Correct "* ]]
# No build was scheduled: the daml stub never logged a start.
run ! grep -q "^start:" "$log_file"
rm -rf "$tmp" "$stub_bin"
rm -f "$log_file"
}

@test "daml-export exits non-zero when java succeeds but artifacts are missing (SUR-3644)" {
tmp=$(mktemp -d)
stub_bin=$(mktemp -d)
log_file=$(mktemp)
write_daml_stub "$stub_bin"
printf '%s\n' '#!/usr/bin/env bash' 'exit 0' >"$stub_bin/java"
chmod +x "$stub_bin/java"

run env PATH="$stub_bin:$PATH" DAML_STUB_LOG="$log_file" DAML_EXPORT_SOURCE_ONLY= \
bash "$DAML_EXPORT" -d "$tmp" -b 0 -e 1 -s 1 -P 5
[ "$status" -ne 0 ]
[[ "$output" == *"missing required files"* ]]
# No build was scheduled: the daml stub never logged a start.
run ! grep -q "^start:" "$log_file"
rm -rf "$tmp" "$stub_bin"
rm -f "$log_file"
}

@test "daml-export does not schedule duplicate builds for same output dir (SUR-3352)" {
tmp=$(mktemp -d)
stub_bin=$(mktemp -d)
Expand Down
12 changes: 12 additions & 0 deletions tests/minikube-test-environment.bats
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,15 @@ teardown() {
[ "$status" -eq 0 ]
grep -qx 'stop' "$MINIKUBE_ARGV_LOG"
}

@test "create passes the default CNI to minikube start (SUR-3648)" {
run env "PATH=$PATH" "MINIKUBE_ARGV_LOG=$MINIKUBE_ARGV_LOG" "$MK_ENV" create
grep -qx 'start' "$MINIKUBE_ARGV_LOG"
grep -qx -- '--cni=calico' "$MINIKUBE_ARGV_LOG"
}

@test "create honors a CNI override on minikube start (SUR-3648)" {
run env "PATH=$PATH" "MINIKUBE_ARGV_LOG=$MINIKUBE_ARGV_LOG" CNI=cilium "$MK_ENV" create
grep -qx 'start' "$MINIKUBE_ARGV_LOG"
grep -qx -- '--cni=cilium' "$MINIKUBE_ARGV_LOG"
}
58 changes: 58 additions & 0 deletions tests/replace-validator.bats
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,64 @@ EOF
[ "$status" -eq 0 ]
}

@test "validateNodesMapped errors and exits non-zero when FROM_NODE has no pod (SUR-3649)" {
TEST_SCRIPT=$(mktemp)
cat >"$TEST_SCRIPT" <<EOF
set -e
source '$REPO_ROOT/bash/includer.sh'
@include log

eval "\$(awk '/^function validateNodesMapped\\(/,/^}\$/' '$TARGET')"

declare -A node2pod=([node-B]=example-pod-2)
validateNodesMapped node2pod app=foo node-A node-B
echo "should-not-reach"
EOF
run bash "$TEST_SCRIPT"
rm -f "$TEST_SCRIPT"
[ "$status" -ne 0 ]
[[ "$output" == *"no pod found for node 'node-A'"* ]]
[[ "$output" == *"app=foo"* ]]
[[ "$output" != *"should-not-reach"* ]]
}

@test "validateNodesMapped errors when TRGT_NODE has no pod (SUR-3649)" {
TEST_SCRIPT=$(mktemp)
cat >"$TEST_SCRIPT" <<EOF
set -e
source '$REPO_ROOT/bash/includer.sh'
@include log

eval "\$(awk '/^function validateNodesMapped\\(/,/^}\$/' '$TARGET')"

declare -A node2pod=([node-A]=example-pod-1)
validateNodesMapped node2pod app=foo node-A node-B
EOF
run bash "$TEST_SCRIPT"
rm -f "$TEST_SCRIPT"
[ "$status" -ne 0 ]
[[ "$output" == *"no pod found for node 'node-B'"* ]]
}

@test "validateNodesMapped succeeds when both nodes are mapped (SUR-3649)" {
TEST_SCRIPT=$(mktemp)
cat >"$TEST_SCRIPT" <<EOF
set -e
source '$REPO_ROOT/bash/includer.sh'
@include log

eval "\$(awk '/^function validateNodesMapped\\(/,/^}\$/' '$TARGET')"

declare -A node2pod=([node-A]=example-pod-1 [node-B]=example-pod-2)
validateNodesMapped node2pod app=foo node-A node-B
echo "validated-ok"
EOF
run bash "$TEST_SCRIPT"
rm -f "$TEST_SCRIPT"
[ "$status" -eq 0 ]
[[ "$output" == *"validated-ok"* ]]
}

@test "replace-validator declares @include commands" {
run grep -E '^@include[[:space:]]+commands\b' "$TARGET"
[ "$status" -eq 0 ]
Expand Down
Loading