Skip to content

Commit 346c6f7

Browse files
committed
test: improve test and fixtures
- split the tests so we can see which ones pass - only test firecracker supported versions (drop 0.24, 0.25) - make a new firecracker fixture so it is simple to use in tests - give tests more descriptive names Signed-off-by: Pablo Barbáchano <pablob@amazon.com>
1 parent c51e08c commit 346c6f7

File tree

4 files changed

+131
-138
lines changed

4 files changed

+131
-138
lines changed

tests/conftest.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,10 +94,11 @@ def test_with_any_microvm(test_microvm_any):
9494
from host_tools import proc
9595
from framework import utils
9696
from framework import defs
97-
from framework.artifacts import ArtifactCollection
97+
from framework.artifacts import ArtifactCollection, FirecrackerArtifact
9898
from framework.microvm import Microvm
9999
from framework.s3fetcher import MicrovmImageS3Fetcher
100100
from framework.scheduler import PytestScheduler
101+
from framework.utils import get_firecracker_version_from_toml
101102

102103
# Tests root directory.
103104
SCRIPT_FOLDER = os.path.dirname(os.path.realpath(__file__))
@@ -503,6 +504,35 @@ def aarch64(body):
503504
assert mitigated, "SPECTREv2 not mitigated {}".format(body)
504505

505506

507+
def firecracker_id(fc):
508+
"""Render a nice ID for pytest parametrize."""
509+
if isinstance(fc, FirecrackerArtifact):
510+
return f"firecracker-{fc.version}"
511+
return None
512+
513+
514+
def firecracker_artifacts(*args, **kwargs):
515+
"""Return all supported firecracker binaries."""
516+
params = {
517+
"min_version": "1.1.0",
518+
"max_version": get_firecracker_version_from_toml(),
519+
}
520+
params.update(kwargs)
521+
return ARTIFACTS_COLLECTION.firecrackers(
522+
*args,
523+
**params,
524+
)
525+
526+
527+
@pytest.fixture(params=firecracker_artifacts(), ids=firecracker_id)
528+
def firecracker_release(request):
529+
"""Return all supported firecracker binaries."""
530+
firecracker = request.param
531+
firecracker.download()
532+
firecracker.jailer().download()
533+
return firecracker
534+
535+
506536
def pytest_generate_tests(metafunc):
507537
"""Implement customized parametrization scheme.
508538

tests/framework/artifacts.py

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,15 +2,18 @@
22
# SPDX-License-Identifier: Apache-2.0
33
"""Define classes for interacting with CI artifacts in s3."""
44

5+
import functools
56
import os
67
import platform
78
import tempfile
89
from shutil import copyfile
910
from enum import Enum
1011
from stat import S_IREAD, S_IWRITE
1112
from pathlib import Path
13+
1214
import boto3
1315
import botocore.client
16+
1417
from framework.defs import DEFAULT_TEST_SESSION_ROOT_PATH, SUPPORTED_KERNELS
1518
from framework.utils import compare_versions
1619
from host_tools.snapshot_helper import merge_memory_bitmaps
@@ -93,7 +96,7 @@ def download(self, target_folder=ARTIFACTS_LOCAL_ROOT, force=False):
9396
Path(self.local_dir()).mkdir(parents=True, exist_ok=True)
9497
if force or not os.path.exists(self.local_path()):
9598
self._bucket.download_file(self._key, self.local_path())
96-
# Artifacts are read only by design.
99+
# Artifacts are read-only by design.
97100
os.chmod(self.local_path(), S_IREAD)
98101

99102
def local_path(self):
@@ -276,11 +279,12 @@ def ssh_key(self):
276279
class FirecrackerArtifact(Artifact):
277280
"""Provides access to associated jailer artifact."""
278281

282+
@functools.lru_cache
279283
def jailer(self):
280284
"""Return a jailer binary artifact."""
281285
# Jailer and FC binaries have different extensions and share
282286
# file name when stored in S3:
283-
# Firecracker binary: v0.22.firecrcker
287+
# Firecracker binary: v0.22.firecracker
284288
# Jailer binary: v0.23.0.jailer
285289
jailer_path = str(Path(self.key).with_suffix(".jailer"))
286290
return Artifact(self.bucket, jailer_path, artifact_type=ArtifactType.JAILER)
@@ -291,6 +295,25 @@ def version(self):
291295
# Get the filename, remove the extension and trim the leading 'v'.
292296
return os.path.splitext(os.path.basename(self.key))[0][1:]
293297

298+
@property
299+
def version_tuple(self):
300+
"""Return the artifact's version as a tuple `(X, Y, Z)`."""
301+
return tuple(int(x) for x in self.version.split("."))
302+
303+
@property
304+
def snapshot_version_tuple(self):
305+
"""Return the artifact's snapshot version as a tuple: `X.Y.0`."""
306+
return self.version_tuple[:2] + (0,)
307+
308+
@property
309+
def snapshot_version(self):
310+
"""Return the artifact's snapshot version: `X.Y.0`.
311+
312+
Due to how Firecracker maps release versions to snapshot versions, we
313+
have to request the minor version instead of the actual version.
314+
"""
315+
return ".".join(str(x) for x in self.snapshot_version_tuple)
316+
294317

295318
class ArtifactCollection:
296319
"""Provides easy access to different artifact types."""

tests/integration_tests/functional/test_cmd_line_parameters.py

Lines changed: 45 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -7,81 +7,64 @@
77
from pathlib import Path
88

99
import host_tools.logging as log_tools
10-
from host_tools.cargo_build import get_firecracker_binaries
11-
from conftest import _test_images_s3_bucket
12-
from framework.artifacts import ArtifactCollection
1310
from framework.builder import MicrovmBuilder, SnapshotBuilder, SnapshotType
14-
from framework.utils import run_cmd, get_firecracker_version_from_toml
11+
from framework.utils import run_cmd
12+
from host_tools.cargo_build import get_firecracker_binaries
1513

1614

17-
def test_describe_snapshot_all_versions(bin_cloner_path):
15+
def test_describe_snapshot_all_versions(bin_cloner_path, firecracker_release):
1816
"""
1917
Test `--describe-snapshot` correctness for all snapshot versions.
2018
19+
For each release create a snapshot and verify the data version of the
20+
snapshot state file.
21+
2122
@type: functional
2223
"""
2324
logger = logging.getLogger("describe_snapshot")
2425
builder = MicrovmBuilder(bin_cloner_path)
25-
artifacts = ArtifactCollection(_test_images_s3_bucket())
26-
# Fetch all firecracker binaries.
27-
# For each binary create a snapshot and verify the data version
28-
# of the snapshot state file.
26+
jailer = firecracker_release.jailer()
27+
target_version = firecracker_release.snapshot_version
28+
29+
logger.info(
30+
"Creating snapshot with Firecracker: %s", firecracker_release.local_path()
31+
)
32+
logger.info("Using Jailer: %s", jailer.local_path())
33+
logger.info("Using target version: %s", target_version)
2934

30-
firecracker_artifacts = artifacts.firecrackers(
31-
max_version=get_firecracker_version_from_toml()
35+
vm_instance = builder.build_vm_nano(
36+
fc_binary=firecracker_release.local_path(),
37+
jailer_binary=jailer.local_path(),
38+
diff_snapshots=True,
3239
)
40+
vm = vm_instance.vm
41+
vm.start()
42+
43+
# Create a snapshot builder from a microvm.
44+
snapshot_builder = SnapshotBuilder(vm)
45+
disks = [vm_instance.disks[0].local_path()]
3346

34-
for firecracker in firecracker_artifacts:
35-
firecracker.download()
36-
jailer = firecracker.jailer()
37-
jailer.download()
38-
39-
target_version = firecracker.base_name()[1:]
40-
# Skip for aarch64, since the snapshotting feature
41-
# was introduced in v0.24.0.
42-
if platform.machine() == "aarch64" and "v0.23" in target_version:
43-
continue
44-
45-
logger.info("Creating snapshot with Firecracker: %s", firecracker.local_path())
46-
logger.info("Using Jailer: %s", jailer.local_path())
47-
logger.info("Using target version: %s", target_version)
48-
49-
# v0.23 does not support creating diff snapshots.
50-
diff_snapshots = "0.23" not in target_version
51-
vm_instance = builder.build_vm_nano(
52-
fc_binary=firecracker.local_path(),
53-
jailer_binary=jailer.local_path(),
54-
diff_snapshots=diff_snapshots,
55-
)
56-
vm = vm_instance.vm
57-
vm.start()
58-
59-
# Create a snapshot builder from a microvm.
60-
snapshot_builder = SnapshotBuilder(vm)
61-
disks = [vm_instance.disks[0].local_path()]
62-
63-
# Version 0.24 and greater have Diff support.
64-
snap_type = SnapshotType.DIFF if diff_snapshots else SnapshotType.FULL
65-
66-
snapshot = snapshot_builder.create(
67-
disks,
68-
vm_instance.ssh_key,
69-
target_version=target_version,
70-
snapshot_type=snap_type,
71-
)
72-
logger.debug("========== Firecracker create snapshot log ==========")
73-
logger.debug(vm.log_data)
74-
vm.kill()
75-
76-
# Fetch Firecracker binary for the latest version
77-
fc_binary, _ = get_firecracker_binaries()
78-
# Verify the output of `--describe-snapshot` command line parameter
79-
cmd = [fc_binary] + ["--describe-snapshot", snapshot.vmstate]
80-
81-
code, stdout, stderr = run_cmd(cmd)
82-
assert code == 0
83-
assert stderr == ""
84-
assert target_version in stdout
47+
# Version 0.24 and greater have Diff support.
48+
snap_type = SnapshotType.DIFF
49+
50+
snapshot = snapshot_builder.create(
51+
disks,
52+
vm_instance.ssh_key,
53+
snapshot_type=snap_type,
54+
)
55+
logger.debug("========== Firecracker create snapshot log ==========")
56+
logger.debug(vm.log_data)
57+
vm.kill()
58+
59+
# Fetch Firecracker binary for the latest version
60+
fc_binary, _ = get_firecracker_binaries()
61+
# Verify the output of `--describe-snapshot` command line parameter
62+
cmd = [fc_binary] + ["--describe-snapshot", snapshot.vmstate]
63+
64+
code, stdout, stderr = run_cmd(cmd)
65+
assert code == 0, stderr
66+
assert stderr == ""
67+
assert target_version in stdout
8568

8669

8770
def test_cli_metrics_path(test_microvm_with_api):

0 commit comments

Comments
 (0)