mirror of
https://github.com/kevinveenbirkenbach/computer-playbook.git
synced 2026-11-10 04:36:40 +00:00
CI deploy jobs were titled with the raw role id, so a run page read as a
column of dash-joined prefixes. They now carry a display name: the category
path as hanzi labels, then the role's README heading or the part of the id
the categories do not already say, whichever is shorter.
utils/roles/display.py owns both directions. Encoding happens once, at
discovery time, as a `label` key on every matrix entry; the workflows render
`<glyph> ${{ matrix.label }}` and keep the glyph as a literal because the
retrigger reads the deploy mode off it.
Decoding is what makes the retrigger keep working. It accepts a display name
with or without its variant shard and a bare role id unchanged, so job names
from runs that predate this still parse and a hand-typed dispatch never has
to spell hanzi. The parser therefore stopped matching an id-shaped tail and
asks the codec instead; a job the codec does not recognise is skipped rather
than counted as a role.
The role selections go out as display names too, so the run title reads like
the jobs it spawns. Four consumers decode them back, each the single place
the value is actually used: the whitelist resolver before it checks the role
directory, the discovery query on its env, and the sequencing and plan CLIs
on their arguments.
Every fragment is joined by `·`, including before the title, and the heading
loses its whitespace and any emoji variation selector. A display name holding
a space would make the space-separated whitelist and priority inputs
unparseable with more than one role.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
332 lines
11 KiB
Python
332 lines
11 KiB
Python
"""Unit tests for :mod:`utils.github.variant.bundles`."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
import unittest
|
|
from unittest.mock import patch
|
|
|
|
from humanfriendly import parse_size
|
|
|
|
from utils.github.variant import bundles as vb
|
|
|
|
|
|
class TestChunkIndices(unittest.TestCase):
|
|
def test_splits_into_consecutive_bundles(self) -> None:
|
|
self.assertEqual(vb.chunk_indices(5, 3), [[0, 1, 2], [3, 4]])
|
|
self.assertEqual(vb.chunk_indices(6, 3), [[0, 1, 2], [3, 4, 5]])
|
|
self.assertEqual(vb.chunk_indices(3, 3), [[0, 1, 2]])
|
|
self.assertEqual(vb.chunk_indices(1, 3), [[0]])
|
|
|
|
|
|
class TestResolveBundleSize(unittest.TestCase):
|
|
def test_default_when_unset(self) -> None:
|
|
self.assertEqual(vb.resolve_bundle_size(""), vb.DEFAULT_BUNDLE_SIZE)
|
|
|
|
def test_explicit_value(self) -> None:
|
|
self.assertEqual(vb.resolve_bundle_size("2"), 2)
|
|
|
|
def test_zero_or_negative_rejected(self) -> None:
|
|
with self.assertRaises(ValueError):
|
|
vb.resolve_bundle_size("0")
|
|
|
|
def test_non_numeric_rejected_cleanly(self) -> None:
|
|
with self.assertRaisesRegex(ValueError, "must be an integer"):
|
|
vb.resolve_bundle_size("three")
|
|
|
|
|
|
class TestExpandApps(unittest.TestCase):
|
|
VARIANTS = { # noqa: RUF012
|
|
"web-app-single": [{}],
|
|
"web-app-three": [{}, {}, {}],
|
|
"web-app-five": [{}, {}, {}, {}, {}],
|
|
}
|
|
|
|
def test_role_within_bundle_size_shows_all_variants(self) -> None:
|
|
self.assertEqual(
|
|
vb.expand_apps(["web-app-three"], self.VARIANTS, 3),
|
|
[{"apps": "web-app-three", "variant": "0,1,2", "variant_slug": "0-1-2"}],
|
|
)
|
|
|
|
def test_missing_variants_treated_as_single(self) -> None:
|
|
self.assertEqual(
|
|
vb.expand_apps(["web-app-unknown"], self.VARIANTS, 3),
|
|
[{"apps": "web-app-unknown", "variant": "", "variant_slug": ""}],
|
|
)
|
|
|
|
def test_per_app_bundle_size_override_wins(self) -> None:
|
|
self.assertEqual(
|
|
vb.expand_apps(
|
|
["web-app-three"],
|
|
self.VARIANTS,
|
|
3,
|
|
bundle_size_per_app={"web-app-three": 1},
|
|
),
|
|
[
|
|
{"apps": "web-app-three", "variant": "0", "variant_slug": "0"},
|
|
{"apps": "web-app-three", "variant": "1", "variant_slug": "1"},
|
|
{"apps": "web-app-three", "variant": "2", "variant_slug": "2"},
|
|
],
|
|
)
|
|
|
|
def test_per_app_override_leaves_other_apps_bundled(self) -> None:
|
|
self.assertEqual(
|
|
vb.expand_apps(
|
|
["web-app-three", "web-app-five"],
|
|
self.VARIANTS,
|
|
3,
|
|
bundle_size_per_app={"web-app-five": 2},
|
|
),
|
|
[
|
|
{"apps": "web-app-three", "variant": "0,1,2", "variant_slug": "0-1-2"},
|
|
{"apps": "web-app-five", "variant": "0,1", "variant_slug": "0-1"},
|
|
{"apps": "web-app-five", "variant": "2,3", "variant_slug": "2-3"},
|
|
{"apps": "web-app-five", "variant": "4", "variant_slug": "4"},
|
|
],
|
|
)
|
|
|
|
def test_role_over_bundle_size_is_split(self) -> None:
|
|
self.assertEqual(
|
|
vb.expand_apps(["web-app-five"], self.VARIANTS, 3),
|
|
[
|
|
{"apps": "web-app-five", "variant": "0,1,2", "variant_slug": "0-1-2"},
|
|
{"apps": "web-app-five", "variant": "3,4", "variant_slug": "3-4"},
|
|
],
|
|
)
|
|
|
|
def test_mixed_list_preserves_app_order(self) -> None:
|
|
out = vb.expand_apps(["web-app-single", "web-app-five"], self.VARIANTS, 3)
|
|
self.assertEqual(
|
|
out,
|
|
[
|
|
{"apps": "web-app-single", "variant": "0", "variant_slug": "0"},
|
|
{"apps": "web-app-five", "variant": "0,1,2", "variant_slug": "0-1-2"},
|
|
{"apps": "web-app-five", "variant": "3,4", "variant_slug": "3-4"},
|
|
],
|
|
)
|
|
|
|
def test_storage_cap_splits_within_bundle_size(self) -> None:
|
|
gb = 1_000_000_000
|
|
out = vb.expand_apps(
|
|
["web-app-three"],
|
|
self.VARIANTS,
|
|
3,
|
|
storages_per_app={"web-app-three": [300 * gb, 300 * gb, 300 * gb]},
|
|
max_storage_bytes=400 * gb,
|
|
)
|
|
self.assertEqual(
|
|
out,
|
|
[
|
|
{"apps": "web-app-three", "variant": "0", "variant_slug": "0"},
|
|
{"apps": "web-app-three", "variant": "1", "variant_slug": "1"},
|
|
{"apps": "web-app-three", "variant": "2", "variant_slug": "2"},
|
|
],
|
|
)
|
|
|
|
|
|
class TestBundleIndices(unittest.TestCase):
|
|
def test_count_only_matches_chunk_indices(self) -> None:
|
|
self.assertEqual(vb.bundle_indices(6, 3), [[0, 1, 2], [3, 4, 5]])
|
|
self.assertEqual(vb.bundle_indices(5, 3), [[0, 1, 2], [3, 4]])
|
|
self.assertEqual(vb.bundle_indices(3, 3), [[0, 1, 2]])
|
|
|
|
def test_storage_cap_opens_new_bundle_early(self) -> None:
|
|
gb = 1_000_000_000
|
|
storages = [206 * gb, 150 * gb, 159 * gb, 148 * gb, 164 * gb, 143 * gb]
|
|
self.assertEqual(
|
|
vb.bundle_indices(6, 3, storages, 400 * gb),
|
|
[[0, 1], [2, 3], [4, 5]],
|
|
)
|
|
|
|
def test_single_variant_over_cap_stands_alone(self) -> None:
|
|
gb = 1_000_000_000
|
|
self.assertEqual(
|
|
vb.bundle_indices(2, 3, [500 * gb, 100 * gb], 400 * gb),
|
|
[[0], [1]],
|
|
)
|
|
|
|
def test_none_storage_falls_back_to_count(self) -> None:
|
|
self.assertEqual(
|
|
vb.bundle_indices(4, 3, [None, None, None, None], 400_000_000_000),
|
|
[[0, 1, 2], [3]],
|
|
)
|
|
|
|
|
|
class TestResolveMaxStorage(unittest.TestCase):
|
|
def test_default_when_unset(self) -> None:
|
|
self.assertEqual(vb.resolve_max_storage(""), int(parse_size("350GB")))
|
|
|
|
def test_explicit_value(self) -> None:
|
|
self.assertEqual(vb.resolve_max_storage("200GB"), int(parse_size("200GB")))
|
|
|
|
def test_zero_disables_cap(self) -> None:
|
|
self.assertIsNone(vb.resolve_max_storage("0"))
|
|
|
|
def test_invalid_rejected(self) -> None:
|
|
with self.assertRaises(ValueError):
|
|
vb.resolve_max_storage("huge")
|
|
|
|
|
|
class TestMain(unittest.TestCase):
|
|
def test_reads_argv_and_prints_json(self) -> None:
|
|
with (
|
|
patch.object(vb, "get_variants", return_value={"web-app-five": [{}] * 5}),
|
|
patch.object(vb, "app_variant_storages", return_value={}),
|
|
patch.dict(
|
|
"os.environ",
|
|
{"INFINITO_VARIANT_BUNDLE_SIZE": "3", "INFINITO_DEPLOY_MODE": ""},
|
|
),
|
|
patch("builtins.print") as mock_print,
|
|
):
|
|
rc = vb.main(['["web-app-five"]'])
|
|
self.assertEqual(rc, 0)
|
|
printed = json.loads(mock_print.call_args.args[0])
|
|
self.assertEqual(
|
|
printed,
|
|
[
|
|
{
|
|
"apps": "web-app-five",
|
|
"variant": "0,1,2",
|
|
"variant_slug": "0-1-2",
|
|
"label": "web-app-five 0,1,2",
|
|
},
|
|
{
|
|
"apps": "web-app-five",
|
|
"variant": "3,4",
|
|
"variant_slug": "3-4",
|
|
"label": "web-app-five 3,4",
|
|
},
|
|
],
|
|
)
|
|
|
|
def test_empty_input_yields_empty_list(self) -> None:
|
|
with (
|
|
patch.object(vb, "get_variants", return_value={}),
|
|
patch.object(vb, "app_variant_storages", return_value={}),
|
|
patch("builtins.print") as mock_print,
|
|
):
|
|
rc = vb.main([""])
|
|
self.assertEqual(rc, 0)
|
|
self.assertEqual(json.loads(mock_print.call_args.args[0]), [])
|
|
|
|
def test_non_list_json_rejected(self) -> None:
|
|
with (
|
|
patch.object(vb, "get_variants", return_value={}),
|
|
patch.object(vb, "app_variant_storages", return_value={}),
|
|
self.assertRaises(SystemExit),
|
|
):
|
|
vb.main(['"web-app-five"'])
|
|
|
|
|
|
class TestSwarmMode(unittest.TestCase):
|
|
def _run_swarm(self, apps_json, variants):
|
|
with (
|
|
patch.object(vb, "get_variants", return_value=variants),
|
|
patch.dict("os.environ", {"INFINITO_DEPLOY_MODE": "swarm"}),
|
|
patch("builtins.print") as mock_print,
|
|
):
|
|
rc = vb.main([apps_json])
|
|
self.assertEqual(rc, 0)
|
|
return json.loads(mock_print.call_args.args[0])
|
|
|
|
def test_one_variant_per_runner(self) -> None:
|
|
printed = self._run_swarm(
|
|
'["web-app-five"]',
|
|
{"web-app-five": [{}] * 5},
|
|
)
|
|
self.assertEqual(
|
|
printed,
|
|
[
|
|
{
|
|
"apps": "web-app-five",
|
|
"variant": str(i),
|
|
"variant_slug": str(i),
|
|
"label": f"web-app-five {i}",
|
|
}
|
|
for i in range(5)
|
|
],
|
|
)
|
|
|
|
def test_every_variant_runs_including_all_off(self) -> None:
|
|
printed = self._run_swarm(
|
|
'["web-app-bbb"]',
|
|
{"web-app-bbb": [{}, {}]},
|
|
)
|
|
self.assertEqual(
|
|
printed,
|
|
[
|
|
{
|
|
"apps": "web-app-bbb",
|
|
"variant": "0",
|
|
"variant_slug": "0",
|
|
"label": "web-app-bbb 0",
|
|
},
|
|
{
|
|
"apps": "web-app-bbb",
|
|
"variant": "1",
|
|
"variant_slug": "1",
|
|
"label": "web-app-bbb 1",
|
|
},
|
|
],
|
|
)
|
|
|
|
def test_variant_tokens_map_one_to_one_without_expansion(self) -> None:
|
|
printed = self._run_swarm(
|
|
'["web-app-five#3", "web-app-five#0", "web-app-bare"]',
|
|
{"web-app-five": [{}] * 5, "web-app-bare": [{}, {}]},
|
|
)
|
|
self.assertEqual(
|
|
printed,
|
|
[
|
|
{
|
|
"apps": "web-app-five",
|
|
"variant": "3",
|
|
"variant_slug": "3",
|
|
"label": "web-app-five 3",
|
|
},
|
|
{
|
|
"apps": "web-app-five",
|
|
"variant": "0",
|
|
"variant_slug": "0",
|
|
"label": "web-app-five 0",
|
|
},
|
|
{
|
|
"apps": "web-app-bare",
|
|
"variant": "0",
|
|
"variant_slug": "0",
|
|
"label": "web-app-bare 0",
|
|
},
|
|
{
|
|
"apps": "web-app-bare",
|
|
"variant": "1",
|
|
"variant_slug": "1",
|
|
"label": "web-app-bare 1",
|
|
},
|
|
],
|
|
)
|
|
|
|
def test_compose_mode_keeps_bundling_and_all_variants(self) -> None:
|
|
with (
|
|
patch.object(vb, "get_variants", return_value={"web-app-bbb": [{}, {}]}),
|
|
patch.object(vb, "app_variant_storages", return_value={}),
|
|
patch.dict("os.environ", {"INFINITO_DEPLOY_MODE": "compose"}, clear=False),
|
|
patch("builtins.print") as mock_print,
|
|
):
|
|
rc = vb.main(['["web-app-bbb"]'])
|
|
self.assertEqual(rc, 0)
|
|
self.assertEqual(
|
|
json.loads(mock_print.call_args.args[0]),
|
|
[
|
|
{
|
|
"apps": "web-app-bbb",
|
|
"variant": "0,1",
|
|
"variant_slug": "0-1",
|
|
"label": "web-app-bbb 0,1",
|
|
}
|
|
],
|
|
)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|