ci/lava: Add LavaFarm class to find LAVA farm from runner tag
authorGuilherme Gallo <guilherme.gallo@collabora.com>
Wed, 15 Feb 2023 01:36:58 +0000 (22:36 -0300)
committerMarge Bot <emma+marge@anholt.net>
Thu, 16 Feb 2023 13:08:41 +0000 (13:08 +0000)
LavaFarm is a class created to handle the different types of LAVA farms
and their tags in Mesa CI. Since specific jobs may require different
types of LAVA farms to run on, it is essential to determine which farm
the runner is running on to configure the job correctly.

LavaFarm provides an easy-to-use interface for checking the runner tag
and returning the corresponding LAVA farm, making it simple for Mesa CI
to configure jobs appropriately. By adding tests for LavaFarm, the team
can ensure that this class is functioning as expected, allowing for the
smooth execution of Mesa CI jobs on the correct LAVA farm.

The tests ensure that get_lava_farm returns the correct LavaFarm value
when given invalid or valid tags and that it returns LavaFarm.UNKNOWN
when no tag is provided. The tests use Hypothesis strategies to generate
various labels and farms for testing.

Example of use:
```
from lava.utils.lava_farm import LavaFarm, get_lava_farm

lava_farm = get_lava_farm()
if lava_farm == LavaFarm.DUMMY:
    # Configure the job for the DUMMY farm
    ...
elif lava_farm == LavaFarm.COLLABORA:
    # Configure the job for the COLLABORA farm
    ...
elif lava_farm == LavaFarm.KERNELCI:
    # Configure the job for the KERNELCI farm
    ...
else:
    # Handle the case where the LAVA farm is unknown
    ...
```

Signed-off-by: Guilherme Gallo <guilherme.gallo@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/21325>

.gitlab-ci/container/debian/x86_build.sh
.gitlab-ci/lava/requirements-test.txt
.gitlab-ci/lava/utils/lava_farm.py [new file with mode: 0644]
.gitlab-ci/tests/conftest.py
.gitlab-ci/tests/utils/test_lava_farm.py [new file with mode: 0644]

index 60055ea..cc39d3e 100644 (file)
@@ -92,7 +92,7 @@ ninja install
 popd
 rm -rf DirectX-Headers
 
-python3 -m pip install -r ${CI_PROJECT_DIR}/.gitlab-ci/lava/requirements.txt
+python3 -m pip install -r .gitlab-ci/lava/requirements.txt
 
 # install bindgen
 RUSTFLAGS='-L native=/usr/local/lib' cargo install \
index a45d291..0ff561d 100644 (file)
@@ -1,5 +1,6 @@
 -r requirements.txt
 freezegun==1.1.0
+hypothesis==6.67.1
 pytest==7.2.1
 pytest-cov==3.0.0
 PyYAML==5.3.1
diff --git a/.gitlab-ci/lava/utils/lava_farm.py b/.gitlab-ci/lava/utils/lava_farm.py
new file mode 100644 (file)
index 0000000..dfd51ab
--- /dev/null
@@ -0,0 +1,35 @@
+import os
+import re
+from enum import Enum
+
+
+class LavaFarm(Enum):
+    """Enum class representing the different LAVA farms."""
+
+    LIMA = 1
+    COLLABORA = 2
+    UNKNOWN = 3
+
+
+LAVA_FARM_RUNNER_PATTERNS: dict[LavaFarm, str] = {
+    # Lima pattern comes first, since it has the same prefix as the
+    # Collabora pattern.
+    LavaFarm.LIMA: r"^mesa-ci-[\x01-\x7F]+-lava-lima$",
+    LavaFarm.COLLABORA: r"^mesa-ci-[\x01-\x7F]+-lava-[\x01-\x7F]+$",
+    LavaFarm.UNKNOWN: r"^[\x01-\x7F]+",
+}
+
+
+def get_lava_farm() -> LavaFarm:
+    """
+    Returns the LAVA farm based on the RUNNER_TAG environment variable.
+
+    :return: The LAVA farm
+    """
+    runner_tag: str = os.getenv("RUNNER_TAG", "unknown")
+
+    for farm, pattern in LAVA_FARM_RUNNER_PATTERNS.items():
+        if re.match(pattern, runner_tag):
+            return farm
+
+    raise ValueError(f"Unknown LAVA runner tag: {runner_tag}")
index 866864d..be71c94 100644 (file)
@@ -3,9 +3,12 @@ from unittest.mock import MagicMock, patch
 import pytest
 import yaml
 from freezegun import freeze_time
+from hypothesis import settings
 
 from .lava.helpers import generate_testsuite_result, jobs_logs_response
 
+settings.register_profile("ci", max_examples=1000, derandomize=True)
+settings.load_profile("ci")
 
 def pytest_configure(config):
     config.addinivalue_line(
diff --git a/.gitlab-ci/tests/utils/test_lava_farm.py b/.gitlab-ci/tests/utils/test_lava_farm.py
new file mode 100644 (file)
index 0000000..e11586c
--- /dev/null
@@ -0,0 +1,41 @@
+import re
+
+import pytest
+from hypothesis import given
+from hypothesis import strategies as st
+from lava.utils.lava_farm import LAVA_FARM_RUNNER_PATTERNS, LavaFarm, get_lava_farm
+
+
+@given(
+    runner_tag=st.text(
+        alphabet=st.characters(
+            min_codepoint=1, max_codepoint=127, blacklist_categories=("C",)
+        ),
+        min_size=1,
+    )
+)
+def test_get_lava_farm_invalid_tags(runner_tag):
+    with pytest.MonkeyPatch().context() as mp:
+        mp.setenv("RUNNER_TAG", runner_tag)
+        assert get_lava_farm() == LavaFarm.UNKNOWN
+
+
+def test_get_lava_farm_no_tag(monkeypatch):
+    monkeypatch.delenv("RUNNER_TAG", raising=False)
+    assert get_lava_farm() == LavaFarm.UNKNOWN
+
+
+@given(
+    st.fixed_dictionaries(
+        {k: st.from_regex(v) for k, v in LAVA_FARM_RUNNER_PATTERNS.items()}
+    )
+)
+def test_get_lava_farm_valid_tags(runner_farm_tag: dict):
+    with pytest.MonkeyPatch().context() as mp:
+        for farm, tag in runner_farm_tag.items():
+            try:
+                mp.setenv("RUNNER_TAG", tag)
+            except ValueError:
+                # hypothesis may generate null bytes in the string
+                continue
+            assert get_lava_farm() == farm