blob: 2c3fa213609ec9d459bc57e443ecefe20e7c6d10 [file]
#!/usr/bin/env vpython3
# Copyright 2025 The LUCI Authors. All rights reserved.
# Use of this source code is governed under the Apache License, Version 2.0
# that can be found in the LICENSE file.
from __future__ import annotations
from dataclasses import dataclass
from google.protobuf.struct_pb2 import Struct
from google.protobuf.timestamp_pb2 import Timestamp
import test_env
from PB.turboci.graph.ids.v1 import identifier
from recipe_engine.internal.turboci.ids import (
AnyIdentifier, check_id, collect_check_ids, from_id, stage_id, to_id, type_url_for, type_urls, wrap_id
)
class TypeURLForTest(test_env.RecipeEngineUnitTest):
def test_ok(self):
self.assertEqual(
type_url_for(Struct()),
"type.googleapis.com/google.protobuf.Struct")
self.assertEqual(
type_url_for(Struct),
"type.googleapis.com/google.protobuf.Struct")
def test_fail(self):
with self.assertRaises(Exception):
type_url_for(None) # pyright: ignore
_testTS = Timestamp(seconds=12345, nanos=7890)
@dataclass
class _id_test_case:
kind: str
ident: AnyIdentifier
ident_str: str
note: str = ""
@property
def name(self):
if self.note:
return f'{self.kind} ({self.note})'
return self.kind
_test_cases: list[_id_test_case] = [
_id_test_case(
"work_plan",
identifier.WorkPlan(id="1234567"),
"L1234567"),
_id_test_case(
"check",
identifier.Check(
work_plan=identifier.WorkPlan(id="1234567"),
id="cool/beans & stuff",
),
"L1234567:Ccool/beans & stuff"),
_id_test_case(
"check_result",
identifier.CheckResult(
check=identifier.Check(
work_plan=identifier.WorkPlan(id="1234567"),
id="cool/beans & stuff"),
idx=3,
),
"L1234567:Ccool/beans & stuff:R3"),
_id_test_case(
"check_edit",
identifier.CheckEdit(
check=identifier.Check(
work_plan=identifier.WorkPlan(id="1234567"),
id="cool/beans & stuff"),
version=_testTS,
),
"L1234567:Ccool/beans & stuff:V12345/7890"),
_id_test_case(
"stage",
identifier.Stage(
work_plan=identifier.WorkPlan(id="1234567"),
is_worknode=True,
id="938215823",
),
"L1234567:N938215823",
note="worknode",
),
_id_test_case(
"stage",
identifier.Stage(
work_plan=identifier.WorkPlan(id="1234567"),
is_worknode=False,
id="some stuff that is awesome",
),
"L1234567:Ssome stuff that is awesome",
),
_id_test_case(
"stage_attempt",
identifier.StageAttempt(
stage=identifier.Stage(
work_plan=identifier.WorkPlan(id="1234567"),
is_worknode=True,
id="938215823"),
idx=3,
),
"L1234567:N938215823:A3",
note="worknode",
),
_id_test_case(
"stage_attempt",
identifier.StageAttempt(
stage=identifier.Stage(
work_plan=identifier.WorkPlan(id="1234567"),
is_worknode=False,
id="some stuff that is awesome"),
idx=3,
),
"L1234567:Ssome stuff that is awesome:A3",
),
_id_test_case(
"stage_edit",
identifier.StageEdit(
stage=identifier.Stage(
work_plan=identifier.WorkPlan(id="1234567"),
is_worknode=True,
id="938215823"),
version=_testTS,
),
"L1234567:N938215823:V12345/7890",
note="worknode",
),
_id_test_case(
"stage_edit",
identifier.StageEdit(
stage=identifier.Stage(
work_plan=identifier.WorkPlan(id="1234567"),
is_worknode=False,
id="some stuff that is awesome"),
version=_testTS,
),
"L1234567:Ssome stuff that is awesome:V12345/7890",
),
]
class ToFromIDTest(test_env.RecipeEngineUnitTest):
def test_ok(self):
for tc in _test_cases:
with self.subTest(kind=tc.name):
self.assertEqual(from_id(tc.ident), tc.ident_str)
self.assertEqual(from_id(wrap_id(tc.ident)), tc.ident_str)
self.assertEqual(to_id(tc.ident_str), wrap_id(tc.ident))
class TestWrap(test_env.RecipeEngineUnitTest):
def test_wrap_id(self):
for tc in _test_cases:
with self.subTest(kind=tc.name):
self.assertIsInstance(wrap_id(tc.ident), identifier.Identifier)
self.assertEqual(wrap_id(tc.ident).WhichOneof('type'), tc.kind)
class TestCollectCheckIDs(test_env.RecipeEngineUnitTest):
def test_ok_str(self):
ids = list(collect_check_ids("hello", "goodbye"))
self.assertListEqual(ids, [
wrap_id(identifier.Check(id="hello")),
wrap_id(identifier.Check(id="goodbye")),
])
def test_ok_ident(self):
ids = list(collect_check_ids(
identifier.Check(work_plan=identifier.WorkPlan(id="123"), id="hello"),
identifier.Check(work_plan=identifier.WorkPlan(id="123"), id="goodbye"),
))
self.assertListEqual(ids, [
wrap_id(identifier.Check(work_plan=identifier.WorkPlan(id="123"), id="hello")),
wrap_id(identifier.Check(work_plan=identifier.WorkPlan(id="123"), id="goodbye")),
])
def test_ok_mix(self):
ids = list(collect_check_ids(
identifier.Check(work_plan=identifier.WorkPlan(id="123"), id="hello"),
"goodbye",
in_workplan="321",
))
self.assertListEqual(ids, [
wrap_id(identifier.Check(work_plan=identifier.WorkPlan(id="123"), id="hello")),
wrap_id(identifier.Check(work_plan=identifier.WorkPlan(id="321"), id="goodbye")),
])
def test_bad_id(self):
with self.assertRaisesRegex(ValueError, 'must not contain ":"'):
list(collect_check_ids("something:stuff"))
class TestStageID(test_env.RecipeEngineUnitTest):
def test_ok(self):
self.assertEqual(stage_id('fleem'), identifier.Stage(id="Sfleem"))
self.assertEqual(stage_id('fleem', in_workplan='123'),
identifier.Stage(
work_plan=identifier.WorkPlan(id="123"), id="Sfleem"))
self.assertEqual(stage_id('fleem', in_workplan='123', is_worknode=True),
identifier.Stage(
work_plan=identifier.WorkPlan(id="123"), id="Nfleem"))
class TestCheckID(test_env.RecipeEngineUnitTest):
def test_ok(self):
self.assertEqual(check_id('fleem'), identifier.Check(id="fleem"))
self.assertEqual(check_id('fleem', in_workplan='123'),
identifier.Check(
work_plan=identifier.WorkPlan(id="123"), id="fleem"))
class TestTypeURLs(test_env.RecipeEngineUnitTest):
def test_ok(self):
urls = list(type_urls(
"type.googleapis.com/fictional.package.Message",
Struct,
))
self.assertEqual(urls, [
"type.googleapis.com/fictional.package.Message",
"type.googleapis.com/google.protobuf.Struct",
])
def test_error(self):
with self.assertRaisesRegex(ValueError, "must start with"):
list(type_urls("fictional.package.Messsage"))
if __name__ == '__main__':
test_env.main()