-
Notifications
You must be signed in to change notification settings - Fork 669
feat: Add BVT Container Tests #17840
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
MadhurAggarwal
wants to merge
4
commits into
4.0
Choose a base branch
from
madagg/add-bvt-container-tests
base: 4.0
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
69c08e2
Add Pi Calc Math Test: CPU/arithmatic, runtime Python sanity check
MadhurAggarwal 9e670fc
Add Network BVT Container Tests
MadhurAggarwal bcaebc0
fix Network test names from http to https
MadhurAggarwal 19756ac
Handle Ruff checks and resolvecopilot comments
MadhurAggarwal File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
4 changes: 4 additions & 0 deletions
4
base/images/tests/cases/runtime/container-base/test_math/Dockerfile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| ARG BASE_IMAGE | ||
| FROM ${BASE_IMAGE} | ||
| RUN dnf install -y python3 && dnf clean all | ||
| COPY pi.py /opt/azl-tests/pi.py |
72 changes: 72 additions & 0 deletions
72
base/images/tests/cases/runtime/container-base/test_math/pi.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,72 @@ | ||
| # SPDX-License-Identifier: MIT | ||
| # Pi calculation adapted from https://github.com/MrBlaise/learnpython/blob/master/Numbers/pi.py | ||
| """Spigot-algorithm Pi calculation, run inside the container for compute validation.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import time | ||
| from collections.abc import Iterator | ||
|
|
||
| PI_1000 = ( | ||
| "3.1415926535897932384626433832795028841971693993751058209749445923078164062862089986280348253421170679821480865132823066470938446095505822317253594081284811174502841027019385211055596446229489549303819644288109756659334461284756482337867831652712019091456485669234603486104543266482133936072602491412" | ||
| "737245870066063155881748815209209628292540917153643678925903600113305305488204665213841469519415116094330572703657595919530921861173819326117931051185480744623799627495673518857527248912279381830119491298336733624406566430860213949463952247371907021798609437027705392171762931767523846748184676694051" | ||
| "320005681271452635608277857713427577896091736371787214684409012249534301465495853710507922796892589235420199561121290219608640344181598136297747713099605187072113499999983729780499510597317328160963185950244594553469083026425223082533446850352619311881710100031378387528865875332083814206171776691473" | ||
| "035982534904287554687311595628638823537875937519577818577805321712268066130019278766111959092164201989" | ||
| ) | ||
|
|
||
| MAX_SECONDS_PER_COMPUTE = 20.0 | ||
|
|
||
|
|
||
| def calc_pi(limit: int) -> Iterator[object]: | ||
|
MadhurAggarwal marked this conversation as resolved.
|
||
| """Calculate Pi digits one at a time via the spigot algorithm.""" | ||
| q, r, t, k, n, step = 1, 0, 1, 1, 3, 3 | ||
| counter = 0 | ||
| while counter != limit + 1: | ||
| if 4 * q + r - t < n * t: | ||
| yield n | ||
| if counter == 0: | ||
| yield "." | ||
| if limit == counter: | ||
| break | ||
| counter += 1 | ||
| nr = 10 * (r - n * t) | ||
| n = ((10 * (3 * q + r)) // t) - 10 * n | ||
| q *= 10 | ||
| r = nr | ||
| else: | ||
| nr = (2 * q + r) * step | ||
| nn = (q * (7 * k) + 2 + (r * step)) // (t * step) | ||
| q *= k | ||
| t *= step | ||
| step += 2 | ||
| k += 1 | ||
| n = nn | ||
| r = nr | ||
|
|
||
|
|
||
| def pi_to_places(places: int) -> str: | ||
| """Return Pi, accurate to the given number of decimal places.""" | ||
| return "".join(str(d) for d in calc_pi(places)) | ||
|
|
||
|
|
||
| def verify_pi_1000() -> bool: | ||
| """Check that Pi to 1000 places matches the known reference value.""" | ||
| return pi_to_places(1000) == PI_1000 | ||
|
|
||
|
|
||
| def verify_pi_n_times_1000(nrange: int = 10, mult: int = 1000) -> bool: | ||
| """Repeatedly compute Pi at growing precision and assert performance (max 20s per computation).""" | ||
| for count in range(nrange + 1): | ||
| places = max(count * mult, 3) | ||
| start = time.time() | ||
| answer = pi_to_places(places) | ||
| if len(answer) != places + 2 or time.time() - start > MAX_SECONDS_PER_COMPUTE: | ||
|
Comment on lines
+61
to
+63
|
||
| return False | ||
| return True | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| import sys | ||
|
|
||
| checks = {"1000": verify_pi_1000, "n1000": verify_pi_n_times_1000} | ||
| sys.exit(0 if checks[sys.argv[1]]() else 1) | ||
22 changes: 22 additions & 0 deletions
22
base/images/tests/cases/runtime/container-base/test_math/test_math.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # SPDX-License-Identifier: MIT | ||
| """Verify the container's python3 computes Pi correctly (Dockerfile adds python3).""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import pytest | ||
|
|
||
| _PI = "/opt/azl-tests/pi.py" | ||
|
|
||
|
|
||
| @pytest.mark.dockerfile() | ||
| def test_pi_1000_places(container_exec_shell) -> None: | ||
| """Pi computed to 1000 places must match the known value.""" | ||
| result = container_exec_shell(f"python3 {_PI} 1000") | ||
| assert result.exit_code == 0, f"Pi(1000) verification failed: {result.output}" | ||
|
|
||
|
|
||
| @pytest.mark.dockerfile() | ||
| def test_pi_n_times_1000_places(container_exec_shell) -> None: | ||
| """Sustained Pi compute (10 x 1000 places) must stay correct and fast.""" | ||
| result = container_exec_shell(f"python3 {_PI} n1000") | ||
| assert result.exit_code == 0, f"Pi series verification failed: {result.output}" |
4 changes: 4 additions & 0 deletions
4
base/images/tests/cases/runtime/container-base/test_network/Dockerfile
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,4 @@ | ||
| ARG BASE_IMAGE | ||
| FROM ${BASE_IMAGE} | ||
| RUN dnf install -y python3 && dnf clean all | ||
| COPY netcheck.py /opt/azl-tests/netcheck.py |
92 changes: 92 additions & 0 deletions
92
base/images/tests/cases/runtime/container-base/test_network/netcheck.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,92 @@ | ||
| # SPDX-License-Identifier: MIT | ||
| """Outbound HTTPS fetch + parse helpers, run inside the container to validate networking.""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import re | ||
| import time | ||
| import urllib.request | ||
| from urllib.error import HTTPError, URLError | ||
|
|
||
| WEATHER_URLS = ( | ||
| "https://iotadbselfhostreportstor.blob.core.windows.net/marinerextendedtests/mockweathergov.html", | ||
| "https://forecast.weather.gov/MapClick.php?lat=47.6786&lon=-122.1316", | ||
| ) | ||
| REPO_CONFIG_URLS = ( | ||
| "https://packages.microsoft.com/azurelinux/3.0/prod/base/x86_64/config.repo", | ||
| "https://packages.microsoft.com/cbl-mariner/2.0/prod/base/x86_64/config.repo", | ||
| ) | ||
|
|
||
|
|
||
| def fetch(url: str, retries: int = 4) -> str: | ||
| """Fetch a URL, retrying transient HTTP errors with exponential backoff, and a 30s timeout to avoid hangs.""" | ||
| for attempt in range(1, retries + 1): | ||
| try: | ||
| with urllib.request.urlopen(urllib.request.Request(url), timeout=30) as resp: # noqa: S310 — https literals only | ||
| return resp.read().decode() | ||
| except HTTPError: | ||
| time.sleep(attempt * 2) | ||
| except URLError: | ||
| break | ||
| return "" | ||
|
|
||
|
|
||
| def fetch_first(urls: tuple[str, ...]) -> str: | ||
| """Return the first non-empty page across the given URLs.""" | ||
| for url in urls: | ||
| page = fetch(url) | ||
| if page: | ||
| return page | ||
| return "" | ||
|
|
||
|
|
||
| def substring_between(source: str, before: str, after: str) -> str: | ||
| """Return the markup-stripped text between two markers, or empty string.""" | ||
| beg = source.find(before) | ||
| if beg < 0: | ||
| return "" | ||
| sub = source[beg + len(before) :] | ||
| end = sub.find(after) | ||
| if end >= 0: | ||
| sub = sub[:end] | ||
| return re.sub(r"<.*?>", "", sub).strip() | ||
|
|
||
|
|
||
| def verify_weather(*, strict: bool = True) -> bool: | ||
| """Fetch Redmond weather; strict requires all forecast fields present.""" | ||
| page = fetch_first(WEATHER_URLS) | ||
| visibility = substring_between(page, "<b>Visibility</b></td>", "</td>") | ||
| dewpoint = substring_between(page, "<b>Dewpoint</b></td>", "</td>") | ||
| humidity = substring_between(page, "<b>Humidity</b></td>", "</td>") | ||
| wind = substring_between(page, "<b>Wind Speed</b></td>", "</td>") | ||
| forecast = substring_between(page, 'alt="Today:', '"') | ||
| print( | ||
| f"weather: bytes={len(page)} humidity={humidity!r} wind={wind!r} " | ||
| f"visibility={visibility!r} dewpoint={dewpoint!r} forecast={forecast!r}" | ||
| ) | ||
| if not (wind and humidity and visibility and dewpoint) and strict: | ||
| return False | ||
| return len(page) > 0 | ||
|
|
||
|
|
||
| def verify_sustained_https(iterations: int = 50, *, strict: bool = True) -> bool: | ||
| """Repeat repo-config fetch; strict requires name+enabled fields each time.""" | ||
| for i in range(iterations): | ||
| page = fetch_first(REPO_CONFIG_URLS) | ||
| name = substring_between(page, "name", "\n") | ||
| enabled = substring_between(page, "enabled", "\n") | ||
| print(f"fetch {i + 1}/{iterations}: bytes={len(page)} name={name!r} enabled={enabled!r}") | ||
| if not (name and enabled) and strict: | ||
| return False | ||
| if len(page) == 0: | ||
| return False | ||
|
Comment on lines
+79
to
+82
|
||
| time.sleep(1) | ||
| return True | ||
|
|
||
|
|
||
| if __name__ == "__main__": | ||
| import sys | ||
|
|
||
| checks = {"weather": verify_weather, "sustained": verify_sustained_https} | ||
| strict = "--strict" in sys.argv | ||
| sys.exit(0 if checks[sys.argv[1]](strict=strict) else 1) | ||
22 changes: 22 additions & 0 deletions
22
base/images/tests/cases/runtime/container-base/test_network/test_network.py
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| # SPDX-License-Identifier: MIT | ||
| """Verify outbound networking from the container (Dockerfile adds python3).""" | ||
|
|
||
| from __future__ import annotations | ||
|
|
||
| import pytest | ||
|
|
||
| _NET = "/opt/azl-tests/netcheck.py" | ||
|
|
||
|
|
||
| @pytest.mark.dockerfile() | ||
| def test_online_service_weather(container_exec_shell) -> None: | ||
| """Test Online Services: a single outbound HTTPS fetch must return a non-empty page.""" | ||
| result = container_exec_shell(f"python3 {_NET} weather") | ||
| assert result.exit_code == 0, f"Outbound HTTPS fetch failed: {result.output}" | ||
|
|
||
|
|
||
| @pytest.mark.dockerfile() | ||
| def test_sustained_https_fetch(container_exec_shell) -> None: | ||
| """Test Core Networking: 50 sequential outbound HTTPS fetches must all return valid repo config.""" | ||
| result = container_exec_shell(f"python3 {_NET} sustained --strict") | ||
| assert result.exit_code == 0, f"Sustained HTTPS fetch failed: {result.output}" |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.