Skip to content
Draft
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
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Cloud = true
30 changes: 30 additions & 0 deletions acceptance/cmd/workspace/genie-clear-description/output.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
round 1: CONVERGED
round 2: CONVERGED
round 3: CONVERGED
round 4: CONVERGED
round 5: CONVERGED
round 6: CONVERGED
round 7: CONVERGED
round 8: CONVERGED
round 9: CONVERGED
round 10: CONVERGED
round 11: CONVERGED
round 12: CONVERGED
round 13: CONVERGED
round 14: CONVERGED
round 15: CONVERGED
round 16: CONVERGED
round 17: CONVERGED
round 18: CONVERGED
round 19: CONVERGED
round 20: CONVERGED
round 21: CONVERGED
round 22: CONVERGED
round 23: CONVERGED
round 24: CONVERGED
round 25: CONVERGED
round 26: CONVERGED
round 27: CONVERGED
round 28: CONVERGED
round 29: CONVERGED
round 30: CONVERGED
128 changes: 128 additions & 0 deletions acceptance/cmd/workspace/genie-clear-description/script
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
# Probe, not meant to be merged: clearing a Genie space description sometimes does not stick on
# cloud (flaky drift in bundle/invariant/no_drift with genie_space.yml.tmpl, ~3% of CI runs). This
# replays the requests the direct engine sends, using plain CLI commands, and polls GET afterwards.
# The poll pattern tells a stale read (old value, then cleared for good) from a lost update
# (cleared, then the old value comes back).
#
# Expected output is CONVERGED for every round; anything else prints the timeline.

# Keep Git Bash on Windows from rewriting /Workspace/... into a C:/Program Files/Git/... path.
export MSYS_NO_PATHCONV=1

me=$($CLI current-user me -o json | jq -r .userName)
parent_path="/Workspace/Users/$me/genie-clear-description-$UNIQUE_NAME"
$CLI workspace mkdirs "$parent_path"

cleanup() {
for id in $(cat LOG.space_ids 2>/dev/null); do
$CLI genie trash-space "$id" > /dev/null
done
$CLI workspace delete --recursive "$parent_path"
}
trap cleanup EXIT

# The flake is rare, so take many samples: rounds run in parallel batches.
rounds=30
batch=10
if [ -n "${CLOUD_ENV:-}" ]; then
polls=15
poll_interval=3
else
polls=3
poll_interval=0
fi

run_round() {
local round=$1 delay=$2
local timeline="LOG.timeline.$round" title="test-genie-space-$UNIQUE_NAME-$round"

# Same create body and missing-parent handling as ResourceGenieSpace.DoCreate. Each round gets a
# parent folder that does not exist yet, as on a bundle's first deploy: the first create fails,
# then the folder is created and the create retried.
local parent="$parent_path/r$round" body space_id
body="{
\"warehouse_id\": \"$TEST_DEFAULT_WAREHOUSE_ID\",
\"title\": \"$title\",
\"description\": \"This is a test genie space\",
\"parent_path\": \"$parent\",
\"serialized_space\": \"{\\\"version\\\":1}\"
}"
if ! $CLI genie create-space -o json --json "$body" > "LOG.create.$round" 2> "LOG.create.err.$round"; then
$CLI workspace mkdirs "$parent"
$CLI genie create-space -o json --json "$body" > "LOG.create.$round"
fi
space_id=$(jq -r .space_id "LOG.create.$round")
rm -f "LOG.create.$round" "LOG.create.err.$round"
echo "$space_id" >> LOG.space_ids
local start=$SECONDS

# The bundle deploy sets permissions right after creating the space, and the drift-check plan
# reads the space before the field-removal update; replay both.
$CLI permissions set genie "$space_id" --json '{"access_control_list": [{"group_name": "users", "permission_level": "CAN_READ"}]}' > /dev/null
$CLI genie get-space "$space_id" --include-serialized-space > /dev/null

sleep "$delay"

# Same update body as ResourceGenieSpace.DoUpdate after the description is removed from config:
# every field is sent, description is force-sent as empty, etag is omitted.
$CLI genie update-space "$space_id" -o json --json "{
\"description\": \"\",
\"title\": \"$title\",
\"warehouse_id\": \"$TEST_DEFAULT_WAREHOUSE_ID\",
\"parent_path\": \"$parent\",
\"serialized_space\": \"{\\\"version\\\":1}\"
}" > "LOG.upd.$round"
local update_desc
update_desc=$(jq -r '.description // ""' "LOG.upd.$round")
echo "t=$((SECONDS - start)) update-response desc='$update_desc' etag=$(jq -r '.etag // ""' "LOG.upd.$round")" > "$timeline"

# One letter per poll: C = description cleared, O = old description returned.
local pattern="" desc version etag
for i in $(seq "$polls"); do
$CLI genie get-space "$space_id" --include-serialized-space -o json > "LOG.get.$round"
desc=$(jq -r '.description // ""' "LOG.get.$round")
version=$(jq -r '.serialized_space // "{}" | fromjson | .version' "LOG.get.$round")
etag=$(jq -r '.etag // ""' "LOG.get.$round")
echo "t=$((SECONDS - start)) get desc='$desc' serialized_space.version=$version etag=$etag" >> "$timeline"
if [ -z "$desc" ]; then
pattern="${pattern}C"
else
pattern="${pattern}O"
fi
sleep "$poll_interval"
done
rm -f "LOG.get.$round" "LOG.upd.$round"

local result
case "$pattern" in
*C*O*) result="LOST_UPDATE" ;;
*C*) [[ "$pattern" == C* ]] && result="CONVERGED" || result="STALE_READ" ;;
*) result="NOT_APPLIED" ;;
esac
if [ -n "$update_desc" ]; then
result="$result (update response still had the old description)"
fi

{
echo "round $round: $result"
if [ "$result" != "CONVERGED" ]; then
echo " delay before update: ${delay}s, polls: $pattern"
sed 's/^/ /' "$timeline"
fi
} > "LOG.result.$round"
}

for round in $(seq "$rounds"); do
# Spread the create->update delay; in the bundle flow plans and uploads sit in between.
delay=0
[ -n "${CLOUD_ENV:-}" ] && delay=$(( (round - 1) % 4 * 4 ))
run_round "$round" "$delay" &
if (( round % batch == 0 )); then
wait
fi
done
wait

for round in $(seq "$rounds"); do
cat "LOG.result.$round"
done
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Cloud = true
Loading