Skip to content

Commit ac1b2d3

Browse files
eriknordmarkclaude
andcommitted
tests/zedagent: add zedagent integration test suite
Adds an Eden testscript suite under tests/zedagent/ that exercises the zedagent microservice end-to-end against a live EVE instance: device info, metrics, app/NI info, attestation FSM, and the /config/-ingest paths consulted at boot. Ten scenarios in two manifests. eden.zedagent.tests.txt (eight tests, run against an onboarded EVE): device_info_completeness, config_items_and_status, maintenance_mode, app_metrics_detail, network_instance_info_metrics, attest_flow (skips without eve.tpm), bootstrap_config_item_ingest, global_config_file_ingest. The two /config-ingest scenarios stage a bootstrap-config.pb or GlobalConfig/global.json after the device is onboarded, freeze /persist/checkpoint so zedagent cannot recreate lastconfig, and reboot. bootstrap_config_item_ingest polls /run/zedagent/ConfigItemValueMap/global.json for its marker (which survives because adam echoes the same configItems back). global_config_file_ingest greps the newlog for the "/config/GlobalConfig contains:" notice instead, because parseConfigItems on adam's first fetch rebuilds globalConfig from defaults+adam's-items and wipes any item adam doesn't push — the log line is the only persistent signal. eden.zedagent-preonboard.tests.txt (two tests, each owns its full eden lifecycle — stop, wipe, eden setup with --eve-bootstrap-file or --eve-config-dir, eden start, no onboard): bootstrap_config_item_ingest_preonboard, global_config_file_ingest_preonboard. With adam never learning the device exists, /config-sourced ConfigItemValueMap stays authoritative throughout the verification window — no controller-takeover race, no log-grep fallback needed. debug.enable.ssh rides inside the staged config in both preonboard tests and gates sshd's iptables open via SSHAuthorizedKeys. SSH readiness doubles as the bug-class canary for the lf-edge/eve#5584/#5775 cert-chain regression class: a zedagent that rejects the bootstrap pb (or fails to apply GlobalConfig) leaves SSHAuthorizedKeys unset and the test times out — a loud, race-free signal. zedagent_test.go provides TestInfo, TestMetric, and TestFlowLog helpers that the testscripts invoke via the `test` command. The preonboard scenarios use preonboard-template.json from PR #1165's tests/network/testdata/. The post-onboard suite was validated against a QEMU-based coverage-instrumented EVE; the six baseline scenarios plus the two /config-ingest tests achieve substantially higher cmd/zedagent coverage than the unit tests alone. Signed-off-by: eriknordmark <erik@zededa.com> Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 6c8de27 commit ac1b2d3

14 files changed

Lines changed: 1707 additions & 0 deletions

tests/zedagent/Makefile

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
DEBUG ?= "debug"
2+
3+
HOSTARCH ?= $(shell uname -m)
4+
HOSTOS ?= $(shell uname -s | tr A-Z a-z)
5+
6+
override HOSTARCH := $(subst aarch64,arm64,$(subst x86_64,amd64,$(HOSTARCH)))
7+
8+
ARCH ?= $(HOSTARCH)
9+
OS ?= $(HOSTOS)
10+
11+
override ARCH := $(subst aarch64,arm64,$(subst x86_64,amd64,$(ARCH)))
12+
13+
WORKDIR ?= $(CURDIR)/../../dist
14+
TESTDIR := tests/$(shell basename $(CURDIR))
15+
BINDIR := $(WORKDIR)/bin
16+
DATADIR := $(WORKDIR)/$(TESTDIR)/
17+
BIN := eden
18+
LOCALBIN := $(BINDIR)/$(BIN)-$(OS)-$(ARCH)
19+
TESTNAME := eden.zedagent
20+
TESTBIN := $(TESTNAME).test
21+
TESTSCN := $(TESTNAME).tests.txt
22+
LOCALTESTBIN := $(TESTBIN)-$(OS)-$(ARCH)
23+
24+
.DEFAULT_GOAL := help
25+
26+
clean:
27+
rm -rf $(LOCALTESTBIN) $(BINDIR)/$(TESTBIN) $(WORKDIR)/$(TESTSCN) $(CURDIR)/$(TESTBIN) $(BINDIR)/$(TESTBIN)
28+
29+
$(BINDIR):
30+
mkdir -p $@
31+
$(DATADIR):
32+
mkdir -p $@
33+
34+
test:
35+
$(LOCALBIN) test $(CURDIR) -v $(DEBUG)
36+
37+
build: setup
38+
39+
testbin: $(TESTBIN)
40+
$(LOCALTESTBIN): $(BINDIR) *.go
41+
CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go test -c -ldflags "-s -w" -o $@ *.go
42+
43+
$(TESTBIN): $(LOCALTESTBIN)
44+
ln -sf $(LOCALTESTBIN) $(CURDIR)/$(TESTBIN)
45+
46+
setup: testbin $(BINDIR) $(DATADIR)
47+
cp -a $(LOCALTESTBIN) $(CURDIR)/$(TESTBIN) $(BINDIR)
48+
cp -a *.tests.txt testdata $(DATADIR)
49+
50+
.PHONY: test build setup clean all testbin
51+
52+
help:
53+
@echo "zedagent eden integration tests"
54+
@echo
55+
@echo "Targets:"
56+
@echo " build build test binary"
57+
@echo " setup build and stage test binary + data"
58+
@echo " test run tests against a running EVE instance"
59+
@echo " clean remove build artifacts"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
eden.escript.test -test.run TestEdenScripts/bootstrap_config_item_ingest_preonboard
2+
eden.escript.test -test.run TestEdenScripts/global_config_file_ingest_preonboard
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
eden.escript.test -test.run TestEdenScripts/device_info_completeness
2+
eden.escript.test -test.run TestEdenScripts/config_items_and_status
3+
eden.escript.test -test.run TestEdenScripts/network_instance_info_metrics
4+
eden.escript.test -test.run TestEdenScripts/app_metrics_detail
5+
eden.escript.test -test.run TestEdenScripts/maintenance_mode
6+
eden.escript.test -test.run TestEdenScripts/global_config_file_ingest
7+
eden.escript.test -test.run TestEdenScripts/bootstrap_config_item_ingest
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Test: per-app and per-volume metrics detail
2+
#
3+
# Deploys an app with an attached volume, waits for it to run, then verifies
4+
# that zedagent publishes non-trivial per-app and per-volume metrics.
5+
#
6+
# Covers: handleDiskMetricCreate/Modify/Impl/Delete (DiskMetric from volumemgr),
7+
# handleAppDiskMetricCreate/lookupAppDiskMetric (AppDiskMetric),
8+
# createVolumeInstanceMetrics, getVolumeResourcesMetrics,
9+
# fillStorageDiskMetrics, fillStorageChildrenMetrics,
10+
# PublishAppInfoToZedCloud, addUserSwInfo,
11+
# PublishVolumeToZedCloud, PublishContentInfoToZedCloud.
12+
13+
{{$info := "test eden.zedagent.test -test.v -test.run TestInfo"}}
14+
{{$metric := "test eden.zedagent.test -test.v -test.run TestMetric"}}
15+
{{$app := "test eden.app.test -test.v"}}
16+
17+
! test eden.reboot.test -test.v -timewait=45m -reboot=0 -count=1 &
18+
19+
# Pre-cleanup: remove stale pod from a previous failed run and wait for EVE to confirm gone.
20+
exec sh -c 'EDEN_HOME=$EDEN_HOME eden pod delete zagent-vm-t1 2>/dev/null || true'
21+
test eden.app.test -test.v -timewait 5m - zagent-vm-t1
22+
23+
# Deploy an app with a volume so disk metrics are generated.
24+
# --volume-size causes volumemgr to create a persistent volume and publish DiskMetric.
25+
eden -t 1m pod deploy --memory 256MB --volume-size=100MB -n zagent-vm-t1 docker://nginx
26+
stdout 'deploy pod zagent-vm-t1'
27+
{{$app}} -timewait 20m RUNNING zagent-vm-t1
28+
29+
# --- app info (PublishAppInfoToZedCloud / addUserSwInfo) ---
30+
# ZInfoApp for our app must be present with a non-empty appID.
31+
eden eve epoch &
32+
{{$info}} -timewait 5m 'InfoContent.ainfo.appID:.+'
33+
stdout 'AppID'
34+
35+
# --- per-app metrics (DiskMetric -> handleDiskMetricImpl -> publishMetrics) ---
36+
# ZMetricMsg.am contains per-app-instance metrics; cpu.total should be > 0.
37+
{{$metric}} -timewait 5m 'am.AppID:.+'
38+
stdout 'cpu'
39+
40+
# --- disk metrics (handleDiskMetricImpl) ---
41+
# Global disk metric must show at least one disk path.
42+
{{$metric}} -timewait 5m 'MetricContent.dm.disk.mountPath:.+'
43+
stdout 'disk'
44+
45+
# --- cleanup ---
46+
eden -t 1m pod delete zagent-vm-t1
47+
stdout 'app zagent-vm-t1 delete done'
48+
{{$app}} -timewait 10m - zagent-vm-t1
49+
stdout 'no app with zagent-vm-t1 found'
50+
51+
exec sh kill_watchdog.sh
52+
wait
53+
54+
# Test's config. file
55+
-- eden-config.yml --
56+
test:
57+
controller: adam://{{EdenConfig "adam.ip"}}:{{EdenConfig "adam.port"}}
58+
eve:
59+
{{EdenConfig "eve.name"}}:
60+
onboard-cert: {{EdenConfigPath "eve.cert"}}
61+
serial: "{{EdenConfig "eve.serial"}}"
62+
model: {{EdenConfig "eve.devmodel"}}
63+
64+
-- kill_watchdog.sh --
65+
pkill -f "eden.reboot.test" || true
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
# Test: remote attestation flow (TPM required)
2+
#
3+
# Verifies that zedagent completes the attestation FSM on a TPM-equipped device:
4+
# nonce request → quote → escrow receipt → COMPLETE state.
5+
# Also verifies that the PCR status is published in ZInfoDevice and that
6+
# forcing a re-attestation cycle exercises the retry path.
7+
#
8+
# Covers: attestModuleStart, handleAttestQuoteCreate/Modify/Impl/Delete,
9+
# handleEncryptedKeyFromDeviceCreate/Modify/Delete,
10+
# publishAttestNonce, publishEncryptedKeyFromController,
11+
# storeIntegrityToken, readIntegrityToken,
12+
# restartAttestation, recordAttestationTry,
13+
# SendAttestQuote (VerifierImpl), SendAttestEscrow (VerifierImpl).
14+
#
15+
# PREREQUISITE: eve.tpm must be "true" in the eden config.
16+
17+
{{$tpm := EdenConfig "eve.tpm"}}
18+
{{if (ne $tpm "true")}}
19+
skip
20+
{{end}}
21+
22+
{{$info := "test eden.zedagent.test -test.v -test.run TestInfo"}}
23+
24+
# Trigger a fresh device info publish.
25+
eden eve epoch &
26+
27+
# --- attestation state complete ---
28+
# ZInfoDevice.attestState should reach ATTEST_STATE_COMPLETE after successful FSM.
29+
# Give it up to 10 minutes for the full nonce/quote/escrow cycle.
30+
{{$info}} -timewait 10m \
31+
'InfoContent.dinfo.attestState:ATTEST_STATE_COMPLETE'
32+
stdout 'ATTEST_STATE_COMPLETE'
33+
34+
# --- PCR status populated ---
35+
# On a TPM device, pcrStatus must be set (RUNNING or PASS).
36+
{{$info}} -timewait 5m \
37+
'InfoContent.dinfo.pcrStatus:.+'
38+
stdout 'InfoContent.dinfo.pcrStatus'
39+
40+
# --- integrity token persisted ---
41+
# Verify the token was written to disk by zedagent (storeIntegrityToken).
42+
exec -t 1m bash check_integrity_token.sh
43+
stdout 'integrity_token_present'
44+
45+
wait
46+
47+
# Test's config. file
48+
-- eden-config.yml --
49+
test:
50+
controller: adam://{{EdenConfig "adam.ip"}}:{{EdenConfig "adam.port"}}
51+
eve:
52+
{{EdenConfig "eve.name"}}:
53+
onboard-cert: {{EdenConfigPath "eve.cert"}}
54+
serial: "{{EdenConfig "eve.serial"}}"
55+
model: {{EdenConfig "eve.devmodel"}}
56+
57+
-- check_integrity_token.sh --
58+
EDEN={{EdenConfig "eden.root"}}/{{EdenConfig "eden.bin-dist"}}/{{EdenConfig "eden.eden-bin"}}
59+
# storeIntegrityToken writes to /persist/status/zedagent/IntegrityToken/
60+
if $EDEN eve ssh ls /persist/status/zedagent/IntegrityToken/ 2>/dev/null | grep -q .; then
61+
echo "integrity_token_present"
62+
exit 0
63+
fi
64+
echo "integrity_token_missing"
65+
exit 1

0 commit comments

Comments
 (0)