Skip to content

Commit fb516d9

Browse files
committed
Add Fedora cloud image validation tests part1
- `verify_fedora_edition_identification`: Validates /etc/os-release fields, fedora-release package version, SUPPORT_END date, URL accessibility, hostnamectl output, and /etc/fedora-release format - `verify_services_started`: Verifies no systemd services are in failed state after boot Signed-off-by: Bala Konda Reddy M <bala12352@gmail.com>
1 parent 290ffd3 commit fb516d9

1 file changed

Lines changed: 196 additions & 0 deletions

File tree

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
# Copyright (c) Microsoft Corporation.
2+
# Licensed under the MIT license.
3+
4+
"""
5+
Fedora Cloud Validation Tests
6+
7+
This test suite validates Fedora cloud image configuration and
8+
functionality. Tests cover OS identification, package management,
9+
boot validation, service status, system logging, and user management.
10+
"""
11+
12+
import re
13+
from typing import Dict
14+
15+
from assertpy.assertpy import assert_that
16+
17+
from lisa import (
18+
Node,
19+
TestCaseMetadata,
20+
TestSuite,
21+
TestSuiteMetadata,
22+
simple_requirement,
23+
)
24+
from lisa.operating_system import Fedora
25+
from lisa.tools import Cat
26+
27+
28+
@TestSuiteMetadata(
29+
area="fedora",
30+
category="functional",
31+
description="""
32+
Fedora Cloud Image Validation Tests.
33+
34+
Validates Fedora cloud image configuration across cloud platforms.
35+
Tests cover: OS identification, package management, boot validation,
36+
service status, system logging, and user management.
37+
""",
38+
)
39+
class FedoraCloudValidation(TestSuite):
40+
"""
41+
Fedora cloud image validation tests.
42+
43+
These tests validate that Fedora cloud images are properly configured
44+
and functional across different cloud platforms (Azure, AWS, etc.).
45+
"""
46+
47+
@TestCaseMetadata(
48+
description="""
49+
Verify Fedora edition self-identification.
50+
51+
Validates /etc/os-release fields, fedora-release package version,
52+
SUPPORT_END date, and URL accessibility for all *_URL fields.
53+
""",
54+
priority=1,
55+
requirement=simple_requirement(supported_os=[Fedora]),
56+
)
57+
def verify_fedora_edition_identification(self, node: Node) -> None:
58+
"""
59+
Verify that the Fedora image correctly identifies itself.
60+
61+
Reads /etc/os-release and checks:
62+
- ID is "fedora"
63+
- VERSION contains VERSION_ID (e.g. "43" is in "Forty Three")
64+
- CPE_NAME includes :fedora:<VERSION_ID>
65+
- Installed fedora-release RPM version matches VERSION_ID
66+
- SUPPORT_END date is still in the future
67+
- PRETTY_NAME and VERSION keys are present
68+
- All *_URL keys return HTTP 2xx/3xx
69+
- hostnamectl mentions "Linux"
70+
- /etc/fedora-release matches "Fedora release N (Name)"
71+
"""
72+
cat = node.tools[Cat]
73+
74+
# Source /etc/os-release and parse into a dict
75+
os_release_content = cat.read("/etc/os-release", force_run=True)
76+
77+
fields: Dict[str, str] = {}
78+
for line in os_release_content.splitlines():
79+
if "=" in line:
80+
key, _, val = line.partition("=")
81+
fields[key.strip()] = val.strip().strip('"')
82+
83+
# ID must be 'fedora'
84+
assert_that(fields.get("ID", "").lower()).described_as(
85+
"/etc/os-release ID must be 'fedora'"
86+
).is_equal_to("fedora")
87+
88+
version_id = fields.get("VERSION_ID", "")
89+
assert_that(version_id).described_as(
90+
"/etc/os-release must have VERSION_ID"
91+
).is_not_empty()
92+
93+
# VERSION string must contain VERSION_ID
94+
version = fields.get("VERSION", "")
95+
assert_that(version).described_as(
96+
f"VERSION ({version}) must contain VERSION_ID ({version_id})"
97+
).contains(version_id)
98+
99+
# CPE_NAME must contain :fedora:<VERSION_ID>
100+
cpe = fields.get("CPE_NAME", "")
101+
assert_that(cpe).described_as(
102+
f"CPE_NAME must contain ':fedora:{version_id}'"
103+
).contains(f":fedora:{version_id}")
104+
105+
# Installed *-release RPM version must match VERSION_ID
106+
rpm_result = node.execute("rpm -qa | grep fedora-release | tail -n1", shell=True)
107+
release_pkg = rpm_result.stdout.strip()
108+
if release_pkg:
109+
rpm_ver = node.execute(f"rpm -q --qf '%{{VERSION}}' {release_pkg}")
110+
assert_that(rpm_ver.stdout.strip()).described_as(
111+
f"Release package version must match VERSION_ID ({version_id})"
112+
).is_equal_to(version_id)
113+
114+
# SUPPORT_END must be in the future
115+
support_end = fields.get("SUPPORT_END", "")
116+
if support_end:
117+
date_check = node.execute(
118+
f'[ "$(date +%s)" -lt "$(date -d "{support_end}" +%s)" ]',
119+
shell=True,
120+
)
121+
assert_that(date_check.exit_code).described_as(
122+
f"SUPPORT_END ({support_end}) must be in the future"
123+
).is_equal_to(0)
124+
125+
# PRETTY_NAME and VERSION fields must exist
126+
assert_that(fields.get("PRETTY_NAME", "")).described_as(
127+
"/etc/os-release must have PRETTY_NAME"
128+
).is_not_empty()
129+
assert_that(version).described_as(
130+
"/etc/os-release must have VERSION"
131+
).is_not_empty()
132+
133+
# hostnamectl must mention Linux (not just Fedora)
134+
hostnamectl = node.execute("hostnamectl")
135+
assert_that(hostnamectl.exit_code).described_as(
136+
"hostnamectl must succeed"
137+
).is_equal_to(0)
138+
assert_that(hostnamectl.stdout).described_as(
139+
"hostnamectl must show 'Linux'"
140+
).contains("Linux")
141+
142+
# /etc/fedora-release must match: Fedora release <N> (<Name>)
143+
fedora_release = cat.read("/etc/fedora-release", force_run=True).strip()
144+
release_match = re.match(r"^Fedora release \d+ \([A-Za-z ]+\)$", fedora_release)
145+
assert_that(release_match is not None).described_as(
146+
f"/etc/fedora-release format invalid: '{fedora_release}'"
147+
).is_true()
148+
149+
node.log.info(
150+
f"Fedora edition validated: VERSION_ID={version_id}, "
151+
f"fedora-release='{fedora_release}'"
152+
)
153+
154+
# Verify all *_URL fields in /etc/os-release return HTTP 2xx or 3xx
155+
url_fields = {k: v for k, v in fields.items() if k.endswith("_URL") and v}
156+
for key, url in url_fields.items():
157+
node.log.info(f"Checking URL: {key}={url}")
158+
curl = node.execute(
159+
"curl -IsSL --connect-timeout 5 --max-time 15 --retry 2"
160+
f' -w "%{{http_code}}" -o /dev/null "{url}"',
161+
shell=True,
162+
no_error_log=True,
163+
timeout=60,
164+
)
165+
http_code = curl.stdout.strip()
166+
assert_that(http_code[:1]).described_as(
167+
f"{key}={url} must return HTTP 2xx/3xx (got {http_code})"
168+
).is_in("2", "3")
169+
node.log.info(f"{key} HTTP {http_code}: OK")
170+
171+
@TestCaseMetadata(
172+
description="""
173+
Verify no failed systemd services after boot.
174+
175+
Checks that all systemd services started successfully by verifying
176+
systemctl reports zero failed units.
177+
""",
178+
priority=1,
179+
requirement=simple_requirement(supported_os=[Fedora]),
180+
)
181+
def verify_services_started(self, node: Node) -> None:
182+
"""
183+
Validate no systemd services are in failed state.
184+
185+
Verifies systemctl --all --failed reports zero loaded failed units.
186+
"""
187+
# Check for failed services
188+
result = node.execute("systemctl --all --failed --no-pager")
189+
node.log.info(f"systemctl --all --failed output:\n{result.stdout}")
190+
191+
# Check for "0 loaded units" in output (success case)
192+
assert_that(result.stdout).described_as(
193+
f"No failed services allowed. Output: {result.stdout}"
194+
).contains("0 loaded units")
195+
196+
node.log.info("No failed services detected")

0 commit comments

Comments
 (0)