feat: add repair timeline read APIs
This commit is contained in:
1 parent
f6a2512e23
commit
36a0caecd8
16 files changed
+1562
-9
No files matched your search
@@ -88,7 +88,7 @@ health_json="$(cat "${health_file}")"
|
||||
|
||||
echo "Checking migrations and required schema..."
|
||||
current_revision="$("${compose[@]}" exec -T backend alembic current 2>/dev/null)"
|
||||
[[ "${current_revision}" == *"0010_begin_repair"* ]]
|
||||
[[ "${current_revision}" == *"0011_repair_timeline"* ]]
|
||||
|
||||
missing_tables="$(
|
||||
"${compose[@]}" exec -T postgres sh -c \
|
||||
@@ -197,6 +197,29 @@ begin_repair_response="$(curl --fail --silent -b "${technician_cookie}" \
|
||||
'{"miner_id":"00000000-0000-0000-0000-000000000981","reason":"CONTROL_BOARD"}'
|
||||
)" == "409" ]]
|
||||
|
||||
smoke_repair_id="$(
|
||||
printf '%s' "${begin_repair_response}" \
|
||||
| python3 -c 'import json, sys; print(json.load(sys.stdin)["data"]["repair_id"])'
|
||||
)"
|
||||
[[ -n "${smoke_repair_id}" ]]
|
||||
readonly_repair_detail="$(
|
||||
curl --fail --silent -b "${readonly_cookie}" \
|
||||
"${base_url}/api/repairs/${smoke_repair_id}"
|
||||
)"
|
||||
[[ "${readonly_repair_detail}" == *'"miner_asset_id":"SMOKE-REPAIR-001"'* ]]
|
||||
[[ "${readonly_repair_detail}" == *'"miner_lifecycle":"in_repair"'* ]]
|
||||
[[ "${readonly_repair_detail}" == *'"latest_event_sequence":2'* ]]
|
||||
readonly_repair_events="$(
|
||||
curl --fail --silent -b "${readonly_cookie}" \
|
||||
"${base_url}/api/repairs/${smoke_repair_id}/events"
|
||||
)"
|
||||
[[ "${readonly_repair_events}" == *'"sequence":1'* ]]
|
||||
[[ "${readonly_repair_events}" == *'"sequence":2'* ]]
|
||||
[[ "${readonly_repair_events}" == *'"event_type":"REPAIR_STARTED"'* ]]
|
||||
[[ "${readonly_repair_events}" == *'"event_type":"INITIAL_NOTE"'* ]]
|
||||
[[ "$(status_for "${technician_cookie}" GET /api/repairs/queue)" == "200" ]]
|
||||
[[ "$(status_for "${technician_cookie}" GET /api/repairs/parts-summary)" == "200" ]]
|
||||
|
||||
room_status="$(status_for "${technician_cookie}" POST /api/rooms '{"name":"Role Matrix Test Room"}')"
|
||||
[[ "${room_status}" == "200" || "${room_status}" == "201" ]]
|
||||
|
||||
|
||||
Executable
+171
@@ -0,0 +1,171 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "${repo_root}"
|
||||
|
||||
project_name="${MINEROPS_TIMELINE_MIGRATION_PROJECT:-minerops-timeline-migration-$$}"
|
||||
empty_database="minerops_timeline_empty"
|
||||
compose=(
|
||||
docker compose
|
||||
--project-name "${project_name}"
|
||||
--env-file .env.dev
|
||||
-f compose.dev.yaml
|
||||
)
|
||||
|
||||
cleanup() {
|
||||
status=$?
|
||||
if (( status != 0 )); then
|
||||
echo
|
||||
echo "Repair Timeline migration test failed. Recent PostgreSQL logs:"
|
||||
"${compose[@]}" logs --no-color --tail 120 postgres || true
|
||||
fi
|
||||
"${compose[@]}" down --volumes --remove-orphans >/dev/null 2>&1 || true
|
||||
exit "${status}"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
if [[ ! -f .env.dev ]]; then
|
||||
echo "Missing .env.dev. Run ./scripts/dev-env-init.sh first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
run_alembic() {
|
||||
"${compose[@]}" run --rm --no-deps backend alembic "$@"
|
||||
}
|
||||
|
||||
echo "Starting disposable PostgreSQL..."
|
||||
"${compose[@]}" up --detach postgres
|
||||
for attempt in $(seq 1 60); do
|
||||
if "${compose[@]}" exec -T postgres sh -ec \
|
||||
'pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"' \
|
||||
>/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
if (( attempt == 60 )); then
|
||||
echo "PostgreSQL did not become ready." >&2
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Building migration image..."
|
||||
"${compose[@]}" build backend
|
||||
|
||||
echo "Upgrading the previous head to Repair Timeline..."
|
||||
run_alembic upgrade 0010_begin_repair
|
||||
previous_revision="$(run_alembic current 2>/dev/null)"
|
||||
[[ "${previous_revision}" == *"0010_begin_repair"* ]]
|
||||
run_alembic upgrade head
|
||||
current_revision="$(run_alembic current 2>/dev/null)"
|
||||
[[ "${current_revision}" == *"0011_repair_timeline"* ]]
|
||||
|
||||
echo "Checking repairs.read permission and role assignments..."
|
||||
"${compose[@]}" exec -T postgres sh -ec \
|
||||
'psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB"' \
|
||||
<<'SQL'
|
||||
DO $$
|
||||
DECLARE
|
||||
v_read_roles TEXT[];
|
||||
v_create_roles TEXT[];
|
||||
BEGIN
|
||||
IF to_regclass('public.repairs') IS NULL
|
||||
OR to_regclass('public.repair_events') IS NULL THEN
|
||||
RAISE EXCEPTION 'Repair tables changed during timeline migration';
|
||||
END IF;
|
||||
|
||||
IF (SELECT count(*) FROM permissions WHERE key = 'repairs.read') <> 1 THEN
|
||||
RAISE EXCEPTION 'repairs.read permission was not registered once';
|
||||
END IF;
|
||||
|
||||
SELECT array_agg(roles.name ORDER BY roles.name)
|
||||
INTO v_read_roles
|
||||
FROM role_permissions
|
||||
JOIN roles ON roles.id = role_permissions.role_id
|
||||
JOIN permissions ON permissions.id = role_permissions.permission_id
|
||||
WHERE permissions.key = 'repairs.read';
|
||||
IF v_read_roles <> ARRAY[
|
||||
'Admin', 'Manager', 'Read Only', 'Technician'
|
||||
] THEN
|
||||
RAISE EXCEPTION 'Unexpected repairs.read role matrix: %', v_read_roles;
|
||||
END IF;
|
||||
|
||||
SELECT array_agg(roles.name ORDER BY roles.name)
|
||||
INTO v_create_roles
|
||||
FROM role_permissions
|
||||
JOIN roles ON roles.id = role_permissions.role_id
|
||||
JOIN permissions ON permissions.id = role_permissions.permission_id
|
||||
WHERE permissions.key = 'repairs.create';
|
||||
IF v_create_roles <> ARRAY['Admin', 'Manager', 'Technician'] THEN
|
||||
RAISE EXCEPTION
|
||||
'repairs.create role matrix changed: %',
|
||||
v_create_roles;
|
||||
END IF;
|
||||
|
||||
INSERT INTO permissions (key, description)
|
||||
VALUES ('repairs.read', 'View repair details and timeline events')
|
||||
ON CONFLICT (key) DO UPDATE
|
||||
SET description = EXCLUDED.description;
|
||||
INSERT INTO role_permissions (role_id, permission_id)
|
||||
SELECT roles.id, permissions.id
|
||||
FROM roles
|
||||
JOIN permissions ON permissions.key = 'repairs.read'
|
||||
WHERE roles.name IN ('Admin', 'Manager', 'Technician', 'Read Only')
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
IF (SELECT count(*) FROM permissions WHERE key = 'repairs.read') <> 1
|
||||
OR (
|
||||
SELECT count(*)
|
||||
FROM role_permissions
|
||||
JOIN permissions
|
||||
ON permissions.id = role_permissions.permission_id
|
||||
WHERE permissions.key = 'repairs.read'
|
||||
) <> 4 THEN
|
||||
RAISE EXCEPTION 'repairs.read seeding is not idempotent';
|
||||
END IF;
|
||||
END
|
||||
$$;
|
||||
SQL
|
||||
|
||||
echo "Downgrading and re-upgrading Repair Timeline..."
|
||||
run_alembic downgrade 0010_begin_repair
|
||||
downgrade_state="$(
|
||||
"${compose[@]}" exec -T postgres sh -ec \
|
||||
'psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d "$POSTGRES_DB" -At' \
|
||||
<<'SQL'
|
||||
SELECT
|
||||
NOT EXISTS (
|
||||
SELECT 1 FROM permissions WHERE key = 'repairs.read'
|
||||
)
|
||||
AND EXISTS (
|
||||
SELECT 1 FROM permissions WHERE key = 'repairs.create'
|
||||
)
|
||||
AND to_regclass('public.repairs') IS NOT NULL
|
||||
AND to_regclass('public.repair_events') IS NOT NULL;
|
||||
SQL
|
||||
)"
|
||||
[[ "${downgrade_state}" == "t" ]]
|
||||
downgraded_revision="$(run_alembic current 2>/dev/null)"
|
||||
[[ "${downgraded_revision}" == *"0010_begin_repair"* ]]
|
||||
|
||||
run_alembic upgrade head
|
||||
reupgraded_revision="$(run_alembic current 2>/dev/null)"
|
||||
[[ "${reupgraded_revision}" == *"0011_repair_timeline"* ]]
|
||||
|
||||
echo "Migrating an empty database from base through head..."
|
||||
"${compose[@]}" exec -T postgres sh -ec \
|
||||
'psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -d postgres \
|
||||
-c "CREATE DATABASE minerops_timeline_empty"' >/dev/null
|
||||
"${compose[@]}" run --rm --no-deps \
|
||||
-e "POSTGRES_DB=${empty_database}" \
|
||||
backend alembic upgrade head
|
||||
|
||||
empty_revision="$(
|
||||
"${compose[@]}" run --rm --no-deps \
|
||||
-e "POSTGRES_DB=${empty_database}" \
|
||||
backend alembic current 2>/dev/null
|
||||
)"
|
||||
[[ "${empty_revision}" == *"0011_repair_timeline"* ]]
|
||||
|
||||
echo "Repair Timeline migration test passed."
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
cd "${repo_root}"
|
||||
|
||||
project_name="${MINEROPS_TIMELINE_TEST_PROJECT:-minerops-repair-timeline-$$}"
|
||||
compose=(
|
||||
docker compose
|
||||
--project-name "${project_name}"
|
||||
--env-file .env.dev
|
||||
-f compose.dev.yaml
|
||||
)
|
||||
|
||||
cleanup() {
|
||||
status=$?
|
||||
if (( status != 0 )); then
|
||||
echo
|
||||
echo "Repair Timeline tests failed. Recent PostgreSQL logs:"
|
||||
"${compose[@]}" logs --no-color --tail 120 postgres || true
|
||||
fi
|
||||
"${compose[@]}" down --volumes --remove-orphans >/dev/null 2>&1 || true
|
||||
exit "${status}"
|
||||
}
|
||||
|
||||
trap cleanup EXIT
|
||||
|
||||
if [[ ! -f .env.dev ]]; then
|
||||
echo "Missing .env.dev. Run ./scripts/dev-env-init.sh first." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Starting disposable Repair Timeline database..."
|
||||
"${compose[@]}" up --detach postgres
|
||||
for attempt in $(seq 1 60); do
|
||||
if "${compose[@]}" exec -T postgres sh -ec \
|
||||
'pg_isready -U "$POSTGRES_USER" -d "$POSTGRES_DB"' \
|
||||
>/dev/null 2>&1; then
|
||||
break
|
||||
fi
|
||||
if (( attempt == 60 )); then
|
||||
echo "PostgreSQL did not become ready." >&2
|
||||
exit 1
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
|
||||
echo "Building Repair Timeline test image..."
|
||||
"${compose[@]}" build backend
|
||||
|
||||
echo "Migrating disposable database..."
|
||||
"${compose[@]}" run --rm --no-deps backend alembic upgrade head
|
||||
|
||||
echo "Running Repair Timeline repository, service, and router tests..."
|
||||
"${compose[@]}" run --rm --no-deps \
|
||||
-v "${repo_root}/backend/tests:/app/tests:ro" \
|
||||
backend python -m unittest -v tests.test_repair_timeline
|
||||
|
||||
echo "Repair Timeline tests passed."
|
||||
Reference in new issue
Block a user