CoolFace
Apppublic

lankasailendra/BMCTESTMAIN

sourceHugging Faceupdated 1d agoView on Hugging Face
0likes
preflight_required_fields.py743 linesDownload Raw Back to scripts
1"""Offline preflight for tenant-required-field resolution and the create gate.2 3    python scripts/preflight_required_fields.py     # exits non-zero on any failure4 5No network, no LLM, no tenant, no app run. The AR form metadata and the identity6helpers are stubbed, so this runs anywhere and costs nothing.7 8What it guards: the tenant scan said "Contact Company" was required on9HPD:IncidentInterface_Create and the harness sent NOTHING for it — the label was10outside the hand-written _UI_REQUIRED_FILL whitelist, so it was reported once as11"(no field mapping)" in console output and then forgotten (2026-09-10). Fields12like that are not mysteries: Contact Company is the company _get_company()13already returns. Now they resolve by identity role, and a create that still has14an unfilled required field does not go out at all.15"""16 17import json18import os19import pathlib20import sys21 22_REF = pathlib.Path(__file__).resolve().parent.parent / "reference" / "itsm"23sys.path.insert(0, str(_REF))24 25from conftest_files import conftest_core as cc  # noqa: E40226from conftest_files.conftest_workflow_errors import WorkflowError  # noqa: E40227 28# Sections below stub cc.ar_form_field_meta to drive the callers that use it.29# The shipped-metadata section at the end exercises the REAL one, so keep a30# handle on it here — before the first stub is installed.31_REAL_AR_FORM_FIELD_META = cc.ar_form_field_meta32 33FAILS = []34 35 36def check(name, ok, detail=""):37    print(f"[{'ok ' if ok else 'FAIL'}] {name}" + (f"  — {detail}" if detail else ""))38    if not ok:39        FAILS.append(name)40 41 42CHAR = lambda n=254: {43    "datatype": "CHAR",44    "max_length": n,45    "required": True,46}  # noqa: E73147ENUM = lambda v: {  # noqa: E73148    "datatype": "ENUM",49    "selection_values": v,50    "max_length": 0,51    "required": True,52}53 54# The real HPD:IncidentInterface_Create required list from a live tenant scan.55INCIDENT_META = {56    "Contact Company": CHAR(),57    "Create Impacted Area from Customer's Location": ENUM(["Yes", "No"]),58    "Description": CHAR(100),59    "Impact": ENUM(["1-Extensive", "4-Minor/Localized"]),60    "Incident Number": CHAR(15),61    "Owner Group": CHAR(60),62    "Phone Number": CHAR(30),63    "Priority": ENUM(["Critical", "Low"]),64    "Reported Source": ENUM(["Direct Input"]),65    "Service Type": ENUM(["User Service Restoration"]),66    "Short Description": CHAR(),67    "Status": ENUM(["New"]),68    "Submitter": CHAR(),69    "Urgency": ENUM(["4-Low"]),70}71 72IDENTITY = {73    "company": "Petramco",74    "first": "Sam",75    "last": "Tester",76    "full": "Sam Tester",77    "group": "Service Desk",78    "org": "IT Support",79    "phone": "555-0100",80}81 82 83def stub(meta, required_names, *, phone=IDENTITY["phone"], company=IDENTITY["company"]):84    cc.ar_form_field_meta = lambda b, h, f: meta85    cc.rest_required_fields = lambda m: list(required_names)86    cc._ui_required_labels = lambda m: []87    cc._get_company = lambda b, h: company88    cc._executor_person_info = lambda b, h: (89        IDENTITY["full"],90        IDENTITY["first"],91        IDENTITY["last"],92    )93    cc._get_support_group = lambda b, h: IDENTITY["group"]94    cc._executor_phone = lambda b, h: phone95    cc.SUPPORT_GROUP = IDENTITY["group"]96    cc.SUPPORT_ORG = IDENTITY["org"]97    cc._REQUIRED_SOURCE_CACHE.clear()98    cc._AR_FORM_FIELD_META_CACHE.clear()99 100 101print("-- a required field name maps to the identity that answers it --")102for name, want in (103    ("Contact Company", "company"),104    ("Customer Company", "company"),105    ("Location Company", "company"),106    ("Customer First Name", "first_name"),107    ("Customer Last Name", "last_name"),108    ("Owner Group", "group"),109    ("Support Group Name", "group"),110    ("Assigned Support Organization", "organization"),111    ("Phone Number", "phone"),112    ("Customer", "full_name"),113    ("Summary", ""),114    ("Work Order Type", ""),115):116    got = cc.required_field_role(name)117    check(f"{name!r} → {want or 'no role'}", got == want, f"got {got!r}")118 119check(120    "an AR-generated key still has no role and stays skipped",121    cc.required_field_role("Incident Number") == ""122    and cc._is_generated_id_field("Incident Number"),123)124 125print("\n-- the resolved values reach the create body --")126stub(INCIDENT_META, list(INCIDENT_META))127body = {"Description": "TC-ITSM-INC-002 create and edit an incident", "Status": "New"}128extra = cc.rest_required_extra_values(129    "https://t",130    {},131    "HPD:IncidentInterface_Create",132    "incident",133    body,134    body["Description"],135)136check(137    "Contact Company gets the tenant company",138    extra.get("Contact Company") == IDENTITY["company"],139    repr(extra.get("Contact Company")),140)141check(142    "Owner Group gets the support group",143    extra.get("Owner Group") == IDENTITY["group"],144    repr(extra.get("Owner Group")),145)146check(147    "Phone Number gets the person's phone, not the case summary",148    extra.get("Phone Number") == IDENTITY["phone"],149    repr(extra.get("Phone Number")),150)151check("Incident Number is still never sent", "Incident Number" not in extra)152check("Submitter is still left to AR", "Submitter" not in extra)153check(154    "enum fields still take their first selection value",155    extra.get("Impact") == "1-Extensive" and extra.get("Priority") == "Critical",156    f"{extra.get('Impact')!r}/{extra.get('Priority')!r}",157)158 159print("\n-- a value too long for the field is trimmed, not rejected by AR --")160stub({"Owner Group": CHAR(10)}, ["Owner Group"], company=IDENTITY["company"])161cc._get_support_group = lambda b, h: "A Very Long Support Group Name"162cc.SUPPORT_GROUP = "A Very Long Support Group Name"163cc._REQUIRED_SOURCE_CACHE.clear()164trimmed = cc.rest_required_extra_values("https://t", {}, "F", "incident", {}, "x")165check(166    "trimmed to the field's max length",167    len(trimmed.get("Owner Group", "")) == 10,168    repr(trimmed.get("Owner Group")),169)170 171print("\n-- a plain custom field no longer blocks the create --")172# This USED to raise. On a customized tenant that behaviour turned every173# customer-added text field into a blocked OOTB run, which is the opposite of174# what the suite is for.175stub(176    {"Contact Company": CHAR(), "Impacted Area By Region": CHAR()},177    ["Contact Company", "Impacted Area By Region"],178)179body = {"Description": "x"}180try:181    cc.finalize_required_fields("https://t", {}, "F", "incident", body)182    check("the create proceeds", True)183    check(184        "the custom field carries a marked placeholder",185        body.get("Impacted Area By Region") == "UAT",186        repr(body.get("Impacted Area By Region")),187    )188    check(189        "and the known field still got its real value",190        body.get("Contact Company") == IDENTITY["company"],191        repr(body.get("Contact Company")),192    )193except WorkflowError as exc:194    check("the create proceeds", False, str(exc)[:140])195 196print("\n-- but a field where any value would be a guess still stops it --")197stub(198    {199        "Contact Company": CHAR(),200        "Impacted Area By Region": {201            "datatype": "ENUM",202            "max_length": 0,203            "required": True,204        },205    },206    ["Contact Company", "Impacted Area By Region"],207)208body = {"Description": "x"}209try:210    cc.finalize_required_fields("https://t", {}, "F", "incident", body)211    check("the create is refused", False, "no WorkflowError raised")212except WorkflowError as exc:213    check("the create is refused", True)214    check(215        "the message names the unfillable field",216        "Impacted Area By Region" in str(exc),217        str(exc)[:120],218    )219    check("and does NOT name the one it filled", "Contact Company:" not in str(exc))220check(221    "the fillable field was still filled before the gate ran",222    body.get("Contact Company") == IDENTITY["company"],223    repr(body.get("Contact Company")),224)225 226print("\n-- a fully resolvable form passes the gate --")227stub(INCIDENT_META, list(INCIDENT_META))228body = {"Description": "TC-ITSM-INC-002 create and edit an incident", "Status": "New"}229try:230    cc.finalize_required_fields(231        "https://t",232        {},233        "HPD:IncidentInterface_Create",234        "incident",235        body,236        body["Description"],237    )238    check("no exception", True)239    check(240        "every required field is now set",241        all(242            str(body.get(f, "")).strip()243            for f in INCIDENT_META244            if f.lower() not in cc._REST_REQUIRED_SKIP245            and not cc._is_generated_id_field(f)246        ),247        str({k: v for k, v in body.items()})[:200],248    )249except WorkflowError as exc:250    check("no exception", False, str(exc)[:160])251 252print("\n-- the gate can be downgraded for one run --")253stub({"Impacted Area By Region": CHAR()}, ["Impacted Area By Region"])254os.environ["BMC_REQUIRED_FIELD_GATE"] = "off"255try:256    cc.finalize_required_fields("https://t", {}, "F", "incident", {})257    check("BMC_REQUIRED_FIELD_GATE=off warns instead of raising", True)258except WorkflowError as exc:259    check("BMC_REQUIRED_FIELD_GATE=off warns instead of raising", False, str(exc)[:100])260finally:261    os.environ.pop("BMC_REQUIRED_FIELD_GATE", None)262 263print("\n-- a CUSTOMIZED tenant must not break an OOTB test --")264# A customer makes their own fields required. An OOTB case that has nothing to265# do with those fields still has to create a record.266CUSTOM_META = {267    "Contact Company": CHAR(),268    "CUST_BusinessJustification": CHAR(200),  # plain custom text269    "CUST_CostCentre": CHAR(30),  # plain custom text, short270    "CUST_Region": {  # custom, menu-backed271        "datatype": "CHAR",272        "max_length": 30,273        "required": True,274        "selection_values": ["East", "West"],275    },276    "CUST_ReviewCount": {"datatype": "INTEGER", "max_length": 0, "required": True},277    "CUST_ReviewedOn": {"datatype": "DATE/TIME", "max_length": 0, "required": True},278    "CUST_Classification": {  # ENUM whose options are hidden279        "datatype": "ENUM",280        "max_length": 0,281        "required": True,282    },283}284stub(CUSTOM_META, list(CUSTOM_META))285body = {"Description": "an OOTB incident case"}286extra = cc.rest_required_extra_values(287    "https://t", {}, "F", "incident", body, "an OOTB incident case"288)289check(290    "a plain custom text field gets a MARKED placeholder",291    extra.get("CUST_BusinessJustification") == "UAT",292    repr(extra.get("CUST_BusinessJustification")),293)294check(295    "a custom menu field takes one of the tenant's OWN options",296    extra.get("CUST_Region") == "East",297    repr(extra.get("CUST_Region")),298)299check(300    "a custom integer gets 0",301    extra.get("CUST_ReviewCount") == "0",302    repr(extra.get("CUST_ReviewCount")),303)304check(305    "a custom date/time gets a real timestamp",306    len(str(extra.get("CUST_ReviewedOn") or "")) > 10,307    repr(extra.get("CUST_ReviewedOn")),308)309check(310    "an ENUM with hidden options is NEVER guessed",311    "CUST_Classification" not in extra,312    repr(extra.get("CUST_Classification")),313)314check(315    "the known field still resolves properly, not as a placeholder",316    extra.get("Contact Company") == IDENTITY["company"],317    repr(extra.get("Contact Company")),318)319 320print("\n-- and the tester can supply values without a code change --")321stub(CUSTOM_META, list(CUSTOM_META))322os.environ["BMC_REQUIRED_FIELD_DEFAULTS"] = (323    '{"CUST_BusinessJustification": "Annual audit", "CUST_Classification": "Internal"}'324)325os.environ["BMC_FIELD_CUST_COSTCENTRE"] = "CC-4471"326try:327    extra = cc.rest_required_extra_values("https://t", {}, "F", "incident", {}, "x")328    check(329        "BMC_REQUIRED_FIELD_DEFAULTS wins over the placeholder",330        extra.get("CUST_BusinessJustification") == "Annual audit",331        repr(extra.get("CUST_BusinessJustification")),332    )333    check(334        "and answers the enum nothing else could",335        extra.get("CUST_Classification") == "Internal",336        repr(extra.get("CUST_Classification")),337    )338    check(339        "BMC_FIELD_<NAME> works too",340        extra.get("CUST_CostCentre") == "CC-4471",341        repr(extra.get("CUST_CostCentre")),342    )343finally:344    os.environ.pop("BMC_REQUIRED_FIELD_DEFAULTS", None)345    os.environ.pop("BMC_FIELD_CUST_COSTCENTRE", None)346 347print("\n-- the gate now fires ONLY where any value would be a guess --")348stub(CUSTOM_META, list(CUSTOM_META))349body = {"Description": "x"}350try:351    cc.finalize_required_fields("https://t", {}, "F", "incident", body)352    check(353        "a customized tenant does not block the create",354        False,355        "expected the hidden enum to gate",356    )357except WorkflowError as exc:358    check(359        "the hidden-options enum is the only blocker",360        "CUST_Classification" in str(exc),361        str(exc)[:130],362    )363    check(364        "the plain custom fields were filled, not gated",365        "CUST_BusinessJustification" not in str(exc)366        and body.get("CUST_BusinessJustification") == "UAT",367    )368    check(369        "and the message points at the override",370        "BMC_REQUIRED_FIELD_DEFAULTS" in str(exc),371    )372 373print("\n-- synthetic fill can be switched off entirely --")374stub(CUSTOM_META, list(CUSTOM_META))375os.environ["BMC_REQUIRED_FIELD_SYNTHETIC"] = "off"376try:377    extra = cc.rest_required_extra_values("https://t", {}, "F", "incident", {}, "x")378    check(379        "no placeholder is invented",380        "CUST_BusinessJustification" not in extra,381        repr(extra.get("CUST_BusinessJustification")),382    )383    check(384        "but a tenant menu is still honoured",385        extra.get("CUST_Region") == "East",386        repr(extra.get("CUST_Region")),387    )388finally:389    os.environ.pop("BMC_REQUIRED_FIELD_SYNTHETIC", None)390 391print("\n-- a failed metadata probe no longer disables the contract --")392cc.ar_form_field_meta = lambda b, h, f: {}  # the probe returns nothing393cc.rest_required_fields = lambda m: ["Contact Company", "CUST_Region"]394cc._REQUIRED_SOURCE_CACHE.clear()395extra = cc.rest_required_extra_values("https://t", {}, "F", "incident", {}, "x")396check(397    "an identity field is still filled with no metadata at all",398    extra.get("Contact Company") == IDENTITY["company"],399    repr(extra.get("Contact Company")),400)401# With no metadata the harness cannot tell a plain text field from a menu-backed402# one. It still fills — an incomplete create is a certain failure, while a403# placeholder at least reaches AR, which names the field if it is wrong — but the404# log must not read like a considered decision.405check(406    "an unknown field is still filled so the create can proceed",407    extra.get("CUST_Region") == "UAT",408    repr(extra.get("CUST_Region")),409)410 411print("\n-- the same roles resolve OFFLINE for the Smart IT fillers --")412# The UI fillers run inside a browser step with no REST session. executor_prep413# has already put these in the environment, so the UI side must reach the same414# answers the REST side does — otherwise a company field gets one value over415# REST and none in the UI.416cc._REQUIRED_SOURCE_CACHE.clear()417os.environ.update(418    {419        "BMC_COMPANY": "Petramco",420        "BMC_FIRST_NAME": "Sam",421        "BMC_LAST_NAME": "Tester",422        "BMC_SUPPORT_GROUP": "Service Desk",423        "BMC_PHONE": "555-0100",424    }425)426try:427    check(428        "Contact Company resolves with no REST session",429        cc.resolve_required_field("Contact Company") == "Petramco",430        repr(cc.resolve_required_field("Contact Company")),431    )432    check(433        "Assignee Support Group resolves offline",434        cc.resolve_required_field("Assignee Support Group") == "Service Desk",435        repr(cc.resolve_required_field("Assignee Support Group")),436    )437    check(438        "a field with no identity role resolves to nothing",439        cc.resolve_required_field("Work Order Type") == "",440    )441finally:442    for _k in (443        "BMC_COMPANY",444        "BMC_FIRST_NAME",445        "BMC_LAST_NAME",446        "BMC_SUPPORT_GROUP",447        "BMC_PHONE",448    ):449        os.environ.pop(_k, None)450    cc._REQUIRED_SOURCE_CACHE.clear()451 452print("\n-- the UI filler writes, then PROVES the field took the value --")453from conftest_files import conftest_ui as cu  # noqa: E402454 455cc._REQUIRED_SOURCE_CACHE.clear()456os.environ["BMC_COMPANY"] = "Petramco"457 458 459class _Pwa:460    """Stands in for the Smart IT frame. `landed` is what the form ended up with."""461 462    def __init__(self, landed=""):463        self.landed = landed464 465 466def _wire(typeahead_ok, landed_after):467    cu.select_smartit_typeahead_combobox = (468        lambda page, label, value, frame=None, timeout=0: typeahead_ok469    )470    cu._smartit_field_value = lambda pwa, label: pwa.landed471    return _Pwa(landed_after)472 473 474try:475    pwa = _wire(True, "Petramco")476    check(477        "a typeahead that took the value reports it",478        cu._fill_identity_required_label(None, pwa, "Contact Company") == "Petramco",479    )480 481    # The one that matters: Smart IT accepts keystrokes into a typeahead but the482    # suggestion is never clicked, so the field is still empty. Claiming it was483    # filled would hide a blocked Save.484    pwa = _wire(True, "")485    check(486        "a typeahead that swallowed the keystrokes reports NOT filled",487        cu._fill_identity_required_label(None, pwa, "Contact Company") == "",488    )489 490    pwa = _wire(True, "Petramco")491    check(492        "a label with no identity role is left to the enum picker",493        cu._fill_identity_required_label(None, pwa, "Work Order Type") == "",494    )495finally:496    os.environ.pop("BMC_COMPANY", None)497    cc._REQUIRED_SOURCE_CACHE.clear()498 499print("\n-- the UI side fills a custom text field too --")500 501 502class _Loc:503    def __init__(self, exists, sink):504        self._exists = exists505        self._sink = sink506 507    @property508    def first(self):  # Playwright locators chain through .first509        return self510 511    def count(self):512        return 1 if self._exists else 0513 514    def is_visible(self, timeout=0):515        return self._exists516 517    def fill(self, value, timeout=0):518        self._sink["value"] = value519 520 521class _TextPwa:522    """A frame where `label` is a plain text input (or is not, when text=False)."""523 524    def __init__(self, text=True):525        self.text = text526        self.sink = {}527 528    @property529    def landed(self):530        return self.sink.get("value", "")531 532    def locator(self, selector):533        return _Loc(self.text, self.sink)534 535 536try:537    cu._smartit_field_value = lambda pwa, label: pwa.landed538    pwa = _TextPwa(text=True)539    check(540        "a custom free-text field gets the marked placeholder",541        cu._fill_custom_required_text(None, pwa, "CUST_BusinessJustification") == "UAT",542        repr(pwa.landed),543    )544 545    pwa = _TextPwa(text=False)  # menu-backed: no input to type into546    check(547        "a menu-backed field is left to the enum picker, not typed into",548        cu._fill_custom_required_text(None, pwa, "CUST_Region") == "",549    )550 551    os.environ["BMC_REQUIRED_FIELD_MARK"] = "UAT-AUTOMATION"552    pwa = _TextPwa(text=True)553    check(554        "BMC_REQUIRED_FIELD_MARK sets the placeholder text",555        cu._fill_custom_required_text(None, pwa, "CUST_Notes") == "UAT-AUTOMATION",556        repr(pwa.landed),557    )558    os.environ.pop("BMC_REQUIRED_FIELD_MARK", None)559 560    os.environ["BMC_REQUIRED_FIELD_SYNTHETIC"] = "off"561    pwa = _TextPwa(text=True)562    check(563        "BMC_REQUIRED_FIELD_SYNTHETIC=off invents nothing on the UI side either",564        cu._fill_custom_required_text(None, pwa, "CUST_Notes") == "",565    )566    os.environ.pop("BMC_REQUIRED_FIELD_SYNTHETIC", None)567finally:568    pass569 570print("\n-- the UI gate matches the REST gate --")571try:572    cu._required_field_gate([], "INC", "form")573    check("nothing unfilled → no exception", True)574except WorkflowError:575    check("nothing unfilled → no exception", False)576 577try:578    cu._required_field_gate(579        ["Impacted Area By Region"], "INC", "Smart IT incident create"580    )581    check("an unfilled required field stops the test before Save", False, "no raise")582except WorkflowError as exc:583    check("an unfilled required field stops the test before Save", True)584    check("and names the field", "Impacted Area By Region" in str(exc), str(exc)[:110])585 586os.environ["BMC_REQUIRED_FIELD_GATE"] = "off"587try:588    cu._required_field_gate(["Impacted Area By Region"], "INC", "form")589    check("BMC_REQUIRED_FIELD_GATE=off warns on the UI side too", True)590except WorkflowError:591    check("BMC_REQUIRED_FIELD_GATE=off warns on the UI side too", False)592finally:593    os.environ.pop("BMC_REQUIRED_FIELD_GATE", None)594 595print("\n-- what a bundle teaches the app when it comes back --")596# The app cannot open the Smart IT form, so the fields Smart IT marks mandatory597# are only ever found on the tester's machine. That knowledge used to die in the598# zip. These checks are the way back.599import sys as _s600 601_s.path.insert(0, str(_REF.parent.parent / "src"))602try:603    from tenant_snapshot import absorb_ui_scan_json, merge_required_fields_into_config604 605    SCAN = json.dumps(606        {607            "scanned": ["incident", "work_order"],608            "ui_required_by_module": {609                "incident": ["Customer", "Product category", "Support group"],610                "work_order": ["Customer", "Language Preference"],611            },612            "rest_required_by_module": {613                "incident": ["Contact Company", "Impact"],614            },615            "field_meta_by_form": {616                "HPD:IncidentInterface_Create": {617                    "Contact Company": {618                        "required": True,619                        "datatype": "CHAR",620                        "max_length": 254,621                    },622                }623            },624        }625    )626    ui_map, rest_map, note = absorb_ui_scan_json(SCAN)627    check(628        "the Smart IT-required fields are read back",629        ui_map.get("incident") == ["Customer", "Product category", "Support group"],630        str(ui_map.get("incident")),631    )632    check(633        "so are the API-required ones",634        rest_map.get("incident") == ["Contact Company", "Impact"],635        str(rest_map.get("incident")),636    )637    check("and it says what it found", "Smart IT-required" in note, note)638 639    merged = merge_required_fields_into_config(640        {641            "ui_required_by_module": {"incident": ["Impact"]},642            "required_fields_by_module": {"incident": ["Status"]},643        },644        ui_map,645        rest_map,646    )647    check(648        "merging keeps what the tenant already knew",649        "Impact" in merged["ui_required_by_module"]["incident"]650        and "Customer" in merged["ui_required_by_module"]["incident"],651        str(merged["ui_required_by_module"]["incident"]),652    )653    check(654        "and the API list is topped up, not replaced",655        set(merged["required_fields_by_module"]["incident"])656        == {"Status", "Contact Company", "Impact"},657        str(merged["required_fields_by_module"]["incident"]),658    )659    check(660        "a junk file teaches nothing and raises nothing",661        absorb_ui_scan_json("not json")[2] != "",662    )663except ImportError as exc:664    print(f"       (tenant_snapshot not importable here: {exc})")665 666print("\n-- the tests stop having to phone the tenant again --")667import os as _os668import tempfile as _tf669 670_tmp = _tf.mkdtemp()671_os.makedirs(_os.path.join(_tmp, "conftest_files"), exist_ok=True)672with open(_os.path.join(_tmp, "ui_required_scan.json"), "w", encoding="utf-8") as fh:673    fh.write(674        json.dumps(675            {676                "rest_required_by_module": {677                    "incident": ["Contact Company", "CUST_Region"]678                },679                "field_meta_by_form": {680                    "HPD:IncidentInterface_Create": {681                        "Contact Company": {682                            "required": True,683                            "datatype": "CHAR",684                            "max_length": 254,685                        },686                        "CUST_Region": {687                            "required": True,688                            "datatype": "CHAR",689                            "max_length": 30,690                            "selection_values": ["East", "West"],691                        },692                    }693                },694            }695        )696    )697 698_real_file = cc.__file__699try:700    cc.__file__ = _os.path.join(_tmp, "conftest_files", "conftest_core.py")701    cc.ar_form_field_meta = _REAL_AR_FORM_FIELD_META702    shipped = cc.shipped_field_meta("HPD:IncidentInterface_Create")703    check(704        "the bundle carries the field descriptions",705        "CUST_Region" in shipped,706        str(sorted(shipped)),707    )708    check(709        "including the menu options",710        shipped.get("CUST_Region", {}).get("selection_values") == ["East", "West"],711    )712 713    # Now simulate the tenant refusing to answer.714    cc._AR_FORM_FIELD_META_CACHE.clear()715    cc._REQUIRED_SOURCE_CACHE.clear()716 717    class _Dead:718        status_code = 500719 720    _real_get = cc.requests.get721    cc.requests.get = lambda *a, **k: _Dead()722    try:723        meta = cc.ar_form_field_meta("https://t", {}, "HPD:IncidentInterface_Create")724        check(725            "a failed call no longer leaves the tests blind",726            "CUST_Region" in meta,727            str(sorted(meta)),728        )729        check(730            "and the menu still comes through",731            meta.get("CUST_Region", {}).get("selection_values") == ["East", "West"],732        )733    finally:734        cc.requests.get = _real_get735finally:736    cc.__file__ = _real_file737    cc._AR_FORM_FIELD_META_CACHE.clear()738 739print(740    f"\n{'ALL PASS' if not FAILS else str(len(FAILS)) + ' FAILURE(S): ' + ', '.join(FAILS)}"741)742sys.exit(1 if FAILS else 0)743