Skip to content

[tests/mock_tests]: Migrate test_vnet VS tests to C++ mock tests - #4815

Open
theasianpianist wants to merge 31 commits into
sonic-net:masterfrom
theasianpianist:migrate-test-vnet-to-mock
Open

[tests/mock_tests]: Migrate test_vnet VS tests to C++ mock tests#4815
theasianpianist wants to merge 31 commits into
sonic-net:masterfrom
theasianpianist:migrate-test-vnet-to-mock

Conversation

@theasianpianist

Copy link
Copy Markdown
Contributor

What I did

Migrated tests/test_vnet.py (the VNET virtual-switch integration suite, 38 test
methods) to fast in-process C++/gtest mock tests in
tests/mock_tests/vnetorch_ut.cpp (41 VNetOrchTest TEST_Fs — several VS
methods split into IPv4/IPv6 and ordered/unordered-ECMP variants). The VS module
is deleted in the same PR so the coverage delta is reviewed at the swap.

Coverage ported (mock equivalents of every test_vnet.py method):

  • VXLAN tunnel bind (tunnel + tunnel-maps + P2MP decap term) and teardown.
  • Per-VNET virtual router vs default-scope reuse of the default VR.
  • VNET tunnel routes, ECMP tunnel routes, route idempotency/updates, route metrics.
  • BFD-monitored (and custom-monitored) endpoints: ECMP, advertisement, mixed
    single+ECMP, priority failover clusters, re-pairing and pinned state.
  • Local routes, directly-connected local-secondary failover, local-primary
    tunnel-term ACL priority routes, local-endpoint alias resolution.
  • overlay_dmac change on the fly, TSA route withdrawal, subnet-decap MP2MP
    terms, vxlan multi-map tunnel-map entries, IPv6 link-local trap route.
  • Duplicate-route graceful handling (the test_vnet_orch_24 regression from
    6e25014).

Shared infra added (used on second use, per the mock-first testing policy):

  • tests/mock_tests/common/mock_test_helpers.{h,cpp} (findAttr SAI-attribute
    assertion helper), and policerorch_ut.cpp refactored onto it.
  • SAI BFD API wired into the mock harness.

tests/vnet_lib.py is intentionally kept — tests/test_vnet2.py still imports
it; it will be removed when test_vnet2.py is migrated in a follow-up.

Why I did it

VNET is the single longest-running and flakiest VS module (~52 min of Docker
virtual-switch CI wall-clock). The VS suite requires a full swss/syncd/redis
container and real kernel/netns stimulus, making it slow and flaky. The
equivalent mock tests run in ~1.8s in-process against the orchagent objects with
the SAI API mocked, reclaiming that CI time and removing the flakiness while
preserving the same behavioral coverage.

This is the second migration in the effort tracked alongside the merged
test_policer POC (#4756); it establishes the reusable SAI-attribute assertion
helper for later ports.

How I verified it

  • Full VNetOrchTest suite: 41/41 passing.
  • Full mock-test suite: 973/973 passing (rebased onto current master, which
    includes namelabelmapper — no regressions).
  • Kernel/netns stimulus (FRR/fpmsyncd routes, neighbors, port oper-status) is
    substituted with the equivalent APP_DB/STATE_DB writes; that netlink→DB
    translation stays covered by the kept test_route / tests_fpmsyncd.
  • Verification uses SAI-API mocking (attribute-list capture + findAttr), the
    established pattern in the mock harness (no readable ASIC_DB). VS
    check_syslog failure-absence assertions map to getSaiFailureStatus(); the
    duplicate-route gate was confirmed strong by temporarily routing
    ITEM_ALREADY_EXISTS through handleSaiFailure and observing the expected
    failure.

Details if related

  • Delivered as logical, unsquashed commits (one concern each) for review; GitHub
    squash-on-merge collapses them at merge time.
  • No orchagent production-code changes — tests only.

Copilot AI lite review requested due to automatic review settings August 4, 2026 18:02
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
There may be pipelines that require an authorized user to comment /azp run to run.

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This pull request migrates the VNET virtual-switch integration test suite to fast in-process C++/gtest mock tests, reducing CI time and flakiness while preserving coverage by asserting the SAI programming via the mock SAI harness.

Changes:

  • Removed the legacy VNET VS test suite (tests/test_vnet.py) as part of the coverage swap.
  • Added a comprehensive C++ mock-test suite for VNET (tests/mock_tests/vnetorch_ut.cpp) and integrated it into the mock test build.
  • Extended the mock-test SAI harness to support BFD API usage and introduced a shared SAI-attribute assertion helper (mock_test_helpers::findAttr), refactoring existing tests to use it.

Reviewed changes

Copilot reviewed 6 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
tests/test_vnet.py Removed VNET VS integration tests as coverage is migrated to mock tests.
tests/mock_tests/vnetorch_ut.cpp New C++/gtest mock-test suite covering VNET/VXLAN/BFD behaviors previously tested in VS.
tests/mock_tests/ut_saihelper.cpp Wires up SAI BFD API in the mock-test SAI initialization/teardown.
tests/mock_tests/mock_orchagent_main.h Exposes sai_bfd_api for mock-test compilation and linking.
tests/mock_tests/common/mock_test_helpers.h Adds shared helper declarations for asserting captured SAI attribute lists.
tests/mock_tests/common/mock_test_helpers.cpp Implements mock_test_helpers::findAttr for captured attribute-list inspection.
tests/mock_tests/policerorch_ut.cpp Refactors attribute lookup to use the shared findAttr helper.
tests/mock_tests/Makefile.am Adds the new VNET unit test and shared helper source to the mock test build.

Comment thread tests/mock_tests/ut_saihelper.cpp
Copilot AI review requested due to automatic review settings August 4, 2026 20:22
@theasianpianist
theasianpianist force-pushed the migrate-test-vnet-to-mock branch from f146d30 to 4cf4eae Compare August 4, 2026 20:22
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 4, 2026 21:27
@theasianpianist
theasianpianist force-pushed the migrate-test-vnet-to-mock branch from 4cf4eae to e4ac62f Compare August 4, 2026 21:27
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

Copilot AI review requested due to automatic review settings August 5, 2026 17:57
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines will not run the associated pipelines, because the pull request was updated after the run command was issued. Review the pull request again and issue a new run command.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

theasianpianist and others added 6 commits August 5, 2026 18:11
…sertions

Introduce tests/mock_tests/common/mock_test_helpers.{h,cpp} as the shared
home for helpers that verify what an orch programs by inspecting the
sai_attribute_t list captured from a mocked SAI call (the mock-test
equivalent of reading an attribute back from ASIC_DB, which the in-process
harness has no populated ASIC_DB for).

The first helper is findAttr(), extracted from the inline lookup in
policerorch_ut.cpp per the on-second-use rule: policerorch_ut.cpp now calls
mock_test_helpers::findAttr() instead of its own copy. Subsequent mock-test
ports (starting with the VNet orch tests) reuse this module rather than
re-deriving attribute-list inspection.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
… check

Introduce tests/mock_tests/vnetorch_ut.cpp, the fixture for migrating
tests/test_vnet.py to C++ mock tests. It subclasses MockOrchTest (which
already builds VNetOrch + VxlanTunnelOrch), brings the default ports up so
those orchs run, and mocks the SAI virtual-router API via the shared
mock_sai_api.h framework using the DEFINE_SAI_GENERIC_API_MOCK_WITH_SET
variant (virtual_router is create/set/remove with no bulk ops).

Because the mock harness has no cfgmgr daemons, the fixture writes the
APP_DB entries vxlanmgr/vrfmgr would have produced (vrfmgr passes VNET
fields through unchanged) instead of the CONFIG_DB entries the VS test
writes.

The first case, VnetCreateProgramsVirtualRouter, drives a VXLAN tunnel +
VNET and asserts VNetOrch programs a SAI virtual router for the VNET -- the
mock-test equivalent of the VS check_vnet_entry() ASIC_DB assertion.
Further cluster-A cases (tunnel maps, tunnel, term entry, tunnel map
entries) build on this fixture.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Bind a VNET to a VXLAN tunnel and verify -- by capturing the attributes
VNetOrch/VxlanTunnelOrch pass to the mocked sai_tunnel_api (the harness
has no populated ASIC_DB) -- the same SAI programming the VS test checks:

- 4 tunnel maps, in creation order VNI->VLAN, VLAN->VNI, VNI->VR, VR->VNI
  (vnet_lib.check_vxlan_tunnel)
- the tunnel (VXLAN, encap src IP, and decap/encap mapper wiring)
- the P2MP tunnel-term entry (default VR, dst IP, action tunnel)
- the two VR<->VNI tunnel-map entries carrying the VNET's VNI, keyed/
  valued by the VNET virtual router (vnet_lib.check_vxlan_tunnel_entry)

Also cover teardown: deleting the VNET (via a DEL_COMMAND pushed through
the consumer, so the delete handler actually runs) removes the two map
entries and the VNET virtual router, and deleting the VXLAN tunnel then
removes the shared tunnel, four maps, and term entry
(vnet_lib.check_del_vxlan_tunnel).

The virtual_router create/remove handlers call through to real libsaivs
so the VR gets a valid OID -- a fabricated OID makes the downstream real
create_route_entry (RouteOrch::addLinkLocalRouteToMe) throw and abort the
bind before any tunnel objects are programmed.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Add mock-test coverage for VNET tunnel route programming -- the C++
equivalent of vnet_lib.check_vnet_routes / check_vnet_ecmp_routes /
check_next_hop_group_member / check_del_vnet_routes:

- single-endpoint route -> one TUNNEL_ENCAP next hop + route entry in
  the VNET's virtual router
- endpoint carrying an inner MAC -> SAI_NEXT_HOP_ATTR_TUNNEL_MAC
- multi-endpoint route -> one next hop per endpoint + an ECMP next hop
  group + one member per endpoint, route pointing at the group
- route delete via DEL_COMMAND -> route entry and tunnel next hop removed

Build VNetRouteOrch (plus its gBfdOrch and gTunneldecapOrch
dependencies, which it dereferences without null-guards) into the
fixture, mock the next_hop, next_hop_group and route SAI APIs, and
assert on the sai_attribute_t lists orchagent programs.

Reset the process-global mock DB (testing_db::reset()) at the start of
each test: MockOrchTest::TearDown() does not flush gDB, so rows written
by one test would otherwise be re-consumed by the next test's
addExistingData()+doTask() and inflate the captured object counts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Add mock-test equivalents of test_vnet.py's route idempotency tests
(test_vnet_orch_13/14/15, the non-BFD idempotency cases):

- VnetEcmpRouteReaddIsIdempotent: re-applying an identical IPv6 ECMP
  route reuses the existing next hop group (no new group/members, same
  OID, nothing removed), then delete tears it down.
- VnetEcmpRouteEndpointUpdateReplacesGroup: changing the endpoint set
  creates a new group, removes the old, and repoints the route;
  deleting twice is idempotent.
- VnetSingleRouteReaddIsIdempotent: re-applying an identical
  single-endpoint route reuses the tunnel next hop and creates no group.

Supporting infrastructure:

- Extend ipAddrEquals/prefixAddrEquals to IPv6 so the helpers and
  findRoute() handle the fd:8:10::32/128 -> fd:8:1::N routes these tests
  use.
- Add STATE_DB assertions (checkStateDbRoute/checkStateDbRouteRemoved/
  checkRouteNotAdvertised), the mock equivalent of
  vnet_lib.check_state_db_routes / check_remove_routes_advertisement.
  VNetRouteOrch writes VNET_ROUTE_TUNNEL_TABLE via a plain Table on
  STATE_DB, which is directly readable here (unlike ASIC_DB).
- Capture in-place route repoints: set_route_entry_attribute is not
  routed through the mock_sai_api framework (its macro only mocks
  create/remove), yet VNetRouteOrch::update_route repoints an ECMP route
  in place on an endpoint change. Swap that single function pointer to a
  trampoline that records the new NEXT_HOP_ID onto the matching captured
  route, so a captured route's next_hop_id reflects its current value
  (mirroring the ASIC_DB read in check_vnet_ecmp_routes).

All 11 VNetOrchTest tests pass; full mock suite 923/923.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Query SAI_API_BFD during the mock SAI init so the global sai_bfd_api
pointer is populated, and declare its extern in mock_orchagent_main.h
alongside the other SAI api-pointer externs. Reset it to nullptr in
uninitSaiApi().

This lets mock tests mock the BFD session API (via
DEFINE_SAI_GENERIC_API_MOCK(bfd, bfd_session)); without the query the
apply-mock helper dereferences a null sai_bfd_api and segfaults. Needed
by the VNET BFD-monitored ECMP route tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
theasianpianist and others added 24 commits August 5, 2026 18:11
Add the BFD counterparts of the non-BFD idempotency tests, the equivalent
of test_vnet_orch_16 and test_vnet_orch_17.

- VnetMonitoredSingleRouteReaddIsIdempotent (test_vnet_orch_16): a
  monitored single-endpoint route programs one tunnel next hop while its
  BFD session is up; re-applying it (while up, and while down then back
  up) neither leaks nor duplicates the next hop; deleting removes it.
- VnetMonitoredEcmpRouteReaddIsIdempotent (test_vnet_orch_17): re-applying
  a monitored ECMP route while all monitors are down keeps it unprogrammed;
  re-applying while up reuses the same next hop group (no new group, none
  removed); deleting removes the group and all its BFD sessions.

Full mock suite: 927/927.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Add the mock equivalent of test_vnet_orch_12: BFD health-monitored ECMP
routes on a VNET created with advertise_prefix=true. Verifies that an
active monitored route is published to STATE_DB ADVERTISE_NETWORK_TABLE
carrying its route profile, that the advertisement follows the route's
active/inactive state, and that its profile follows a make-before-break
endpoint/profile change (test_profile -> test_profile2).

Extend setVnet with an advertise_prefix flag and setVnetRouteMonitored
with a profile field, and add a checkRouteAdvertised helper (the mock
equivalent of vnet_lib.check_routes_advertisement). Both helper signature
changes are backward-compatible optional parameters.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Add the mock equivalent of test_vnet_orch_11: mixed single-endpoint and
ECMP BFD-monitored routes that share BFD sessions. A single-endpoint
monitored route programs one tunnel next hop (no group); an overlapping
ECMP monitored route programs a group whose members follow BFD state; a
monitor shared between routes is a single ref-counted BFD session removed
only when its last referencing route is deleted.

Run the scenario for both unordered and ordered ECMP, mirroring the VS
test's ordered_ecmp parametrization: enableOrderedEcmp() writes
SWITCH_TABLE:switch ordered_ecmp=true so VNET ECMP groups are programmed
as SAI_NEXT_HOP_GROUP_TYPE_DYNAMIC_ORDERED_ECMP with per-member
SAI_NEXT_HOP_GROUP_MEMBER_ATTR_SEQUENCE_ID, and checkGroupMember asserts
the sequence ids (mock equivalent of vnet_lib.check_next_hop_group_member).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Add the mock equivalent of test_vnet_orch_18: a priority
(primary/secondary) VNET tunnel route whose endpoints are health-checked
by custom monitors driven through STATE_DB VNET_MONITOR_TABLE, with no
SAI BFD sessions.

Fixture/infra changes reused by the rest of the custom-monitoring
cluster (tests 19-23, 25-27):

- Wire a MonitorOrch into the fixture (registered in gDirectory the way
  orchdaemon does) so STATE_DB VNET_MONITOR_TABLE writes are forwarded to
  VNetRouteOrch, exactly as gMonitorOrch does in production.
- setVnetRoutePriority(): write a VNET_ROUTE_TUNNEL row with primary /
  monitoring / adv_prefix; updateMonitorSessionState(): drive a single
  monitor up/down via a Consumer SET (mock update_monitor_session_state).
- checkPriorityRoute(): assert the SAI programming for the active
  endpoint subset -- a single active endpoint points at that endpoint's
  tunnel next hop, several at an unordered-ECMP group whose members are
  exactly the active endpoints (mock check_priority_vnet_ecmp_routes).
- checkCustomMonitorAppDb()/checkCustomMonitorDeleted(): assert the APP_DB
  VNET_MONITOR_TABLE monitor-session rows.
- setVnet(): optional overlay_dmac field.
- Make findRoute() active-aware (last created net of removals) so a route
  removed and re-added within one test resolves to the current entry.

The test walks the full failover ladder: all monitors down (route not
programmed / adv_prefix not advertised), all up (primary subset only),
primaries dropping one at a time down to secondary fallback, full
withdrawal when every endpoint is down, re-add on secondary, switch back
to primary, and secondary churn not disturbing a primary-active route;
then deletes the route and confirms every monitor session is removed.
STATE_DB active_endpoints remain the authoritative active-set check.

Full mock suite 931/931.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Port test_vnet_orch_19-22 (priority/adv_prefix custom-monitored routes) to
VNetOrchTest:

- VnetTwoPriorityRoutesOverlappingGroups (test 19): two routes over the same
  four endpoints with different primary subsets and separate adv_prefixes;
  per-route independent monitors, primary preference, secondary fallback and
  per-route advertisement (with/without profile) as endpoints flap.
- VnetSingleEndpointPriorityRouteSwitchover (test 20): single-endpoint
  primary/secondary switchover -- the route points directly at one endpoint's
  tunnel next hop (never a group) and prefers the primary while it is up.
- VnetPriorityRoutesSharedAdvPrefixRefcount (test 21): three IPv6 routes
  sharing one adv_prefix; the advertisement is reference-counted and withdrawn
  only when the last contributor is deleted; includes add-after-advertise.
- VnetPriorityRouteReaddAndPrimarySwap (test 22): identical re-add is a no-op;
  swapping the primary to currently-down endpoints keeps the route on its
  active set; a full endpoint-set change moves it; and a no-secondary route is
  custom-monitored without any SAI BFD session.

Also fix delVnetRoute() to remove the deleted row from the backing mock DB in
addition to the Consumer DEL push: setVnetRoute*() uses addExistingData(), which
re-enqueues every current row as a SET, so a row left behind after delete would
resurrect the route. These are the first tests to delete a route and then add
another within one test, which is what exposes it.

Full mock suite 935/935.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Add VnetCustomMonitorOverlayDmacUpdate, the mock equivalent of
test_vnet_orch_23: a VNET can be created, deleted and re-created
repeatedly with its overlay_dmac updated; each custom-monitor APP_DB
row a route creates carries the VNET's current overlay_dmac, and
updating the dmac while routes exist rewrites every monitor row via
updateAllMonitoringSession. An empty-dmac update is a no-op. Also
exercises route re-add + advertisement after a dmac change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Add VnetTunnelRouteMetricValues, the mock equivalent of
test_vnet_orch_33. metric is a passthrough field: VNetCfgRouteOrch
mirrors it verbatim into APP_DB VNET_ROUTE_TUNNEL_TABLE and
VNetRouteOrch does not act on it. The test asserts that a full range
of metric values (0..20) does not disturb route programming -- each
single-endpoint route still programs a tunnel encap next hop and an
active STATE_DB entry -- and that the metric round-trips into APP_DB.

Extends setVnetRoute with an optional metric field.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
…over (29)

Port test_vnet_orch_29: a custom-monitored priority route whose secondary
endpoints are directly-connected/local. Adds the local-endpoint fixture
infrastructure reused by the remaining local tests:

- createL3Interface(port, ipPrefix): write APP_INTF_TABLE rows + drive
  gIntfsOrch (mock of create_l3_intf + add_ip_address).
- addNeighbor(port, ip, mac): write APP_NEIGH_TABLE + drive gNeighOrch so
  isLocalEndpoint() resolves the neighbor and the route reuses the IP next
  hop gNeighOrch creates (mock of add_neighbor / neighsyncd).
- setVnetRoutePriority gains a check_directly_connected flag.
- checkEndpointIsLocal/Remote assert an active endpoint's next hop type
  (SAI_NEXT_HOP_TYPE_IP vs TUNNEL_ENCAP) -- the directly-connected
  distinction STATE_DB active_endpoints alone cannot show.

The failover ladder mirrors test 18, but the secondary subset {9.1.0.3,
9.1.0.4} is local (IP next hops) while the primary {9.1.0.1,9.1.0.2} is
remote (tunnel-encap). Primary-active states use the full priority-route
group check; local secondary states are backbone-checked via STATE_DB plus
per-endpoint locality assertions (as the VS test does).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
…route (28)

Mock equivalent of test_vnet_orch_28: a custom-monitored priority route
whose primary endpoint is directly-connected/local, exercising the
tunnel-termination ACL VNetRouteOrch programs for local endpoints.

Unique coverage vs the other priority tests: no tunnel-term ACL rule
exists before the route; creating the route programs a redirect ACL rule
(DST_IP=vip, TUNNEL_TERM, redirect to the local endpoint IP, priority
9998) whose table type carries the REDIRECT + COUNTER actions -- even
before any monitor is up, since the ACL follows the local endpoint, not
route health; and the local endpoint's next hop persists across a
primary->secondary->primary flap while the remote endpoint's tunnel next
hop is created/removed on demand (active next-hop set 1->2->1).

The ACL rule's APP_DB->SAI translation is covered by aclorch_ut, so the
new checkTunnelTermAclRule/checkNoTunnelTermAclRules helpers assert at the
VNet->ACL (APP_DB) boundary; the VS test asserts the resulting SAI ACL
entry in ASIC_DB. Adds an activeEndpointNexthops helper (the mock view of
the ASIC_DB next hops the VS test counts).

Full mock suite 939/939; VNET suite 27/27.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Port test_vnet_local_route_single (30) and test_vnet_local_route_ecmp
(31) to the vnetorch mock suite.

VNET *local* routes (non-empty nexthop list) are delegated by
VNetRouteOrch to gRouteOrch, which programs them through its route and
next-hop-group-member bulkers. Those bulkers copy the SAI
create/remove/set_*_route_entries and create/remove_next_hop_group_members
function pointers at construction time -- before PostSetUp() applies the
gmock SAI mock -- so the bulk calls bypass the gmock global and were
invisible to the existing captures.

Install plain function-pointer trampolines for the bulk route-entry,
bulk route-entry-attribute-set, and bulk NHG-member APIs in a new
ApplySaiMock() override, which PrepareSai() runs before any Orch is
constructed, and restore them in PreTearDown() after RestoreSaiApis().
The bulk set_route_entries_attribute trampoline is required to observe
the in-place NEXT_HOP_ID repoint an ECMP endpoint-set change performs.

Add local-route helpers: setPortOperStatus() brings a fixture port
oper-up (via a port_state_change notification) so neighbors learned on it
yield programmable, non-IFDOWN next hops; createVnetL3Interface() binds a
VNET RIF; setVnetLocalRoute()/delVnetLocalRoute() drive the APP_DB
VNET_ROUTE_TABLE; checkVnetLocalRoute()/checkVnetLocalRouteRemoved()
assert the SAI programming (direct IP next hop for a single nexthop,
unordered ECMP group + members for multiple), the mock equivalent of
vnet_lib.check_vnet_local_routes / check_vnet_local_route_nexthops /
check_del_vnet_local_routes.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Add VnetMonitoredEcmpRouteTsaWithdrawsAndRestores, the mock equivalent of
test_vnet_orch_25. Drives a BFD-monitored ECMP VNET route through a
Traffic-Shift-Away cycle: with all monitors up the route is programmed over
the ECMP group; enabling TSA (BGP_DEVICE_GLOBAL|STATE tsa_enabled) tears down
every BFD session and withdraws the route (STATE_DB inactive) while the group
persists; clearing TSA recreates the sessions (initially down) so the route
stays withdrawn until the monitors report up again, at which point it is
restored over the same group; deleting the route removes the group and its
sessions.

Adds a setTsa(bool) helper that drives BgpGlobalStateOrch::doTask ->
BfdOrch::handleTsaStateChange, and registers gBfdOrch in gDirectory in
PostSetUp so BgpGlobalStateOrch can resolve BfdOrch for TSA (mirrors
orchdaemon.cpp).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Add VnetDefaultScopeReusesDefaultVirtualRouter, the mock equivalent of
test_vnet_orch_5 / vnet_lib.check_default_vnet_entry. A VNET with scope=default
reuses the global default virtual router (gVirtualRouterId) instead of creating
a per-VNET one, so binding it must not call create_virtual_router (asserted
Times(0)); the VXLAN tunnel is still fully programmed and its VR<->VNI
tunnel-map entries are keyed by the default VR carrying the VNI. Deleting the
VNET removes its map entries without removing the default VR, and deleting the
tunnel tears down the shared tunnel/maps/term.

Extends setVnet() with an optional scope field.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Port test_vnet_ip2me_link_local to the vnetorch mock suite. A non-default
scope VNET VR gets an fe80::/10 link-local trap route installed at VR
creation (VNetVrfObject::createObj -> RouteOrch::addLinkLocalRouteToMe) that
forwards matched control packets to the CPU, and the route is torn down when
the VNET is deleted (~VNetVrfObject -> delLinkLocalRouteToMe).

VnetInstallsIpv6LinkLocalTrapRoute asserts exactly one fe80::/10 route is
programmed in the VNET's own VR (not the default VR), with packet action
FORWARD and a next hop set to the CPU port, and that deleting the VNET
removes it. The link-local route flows through the single create_route_entry
(captured in m_rt.routes), unlike VNET tunnel routes, so its vr / action /
next-hop are directly assertable. Adds a packet_action field to the route
capture struct.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Port test_vnet_orch_local_endpoint_alias_resolution to the vnetorch mock
suite. A custom-monitored, check_directly_connected route whose endpoints
resolve to directly-connected local endpoints: the routes are added before
the neighbors exist (so the endpoint NextHopKey is cached unresolved), then
the neighbors are added and the monitors brought up. The single-endpoint
route resolves to point directly at the local endpoint's SAI_NEXT_HOP_TYPE_IP
next hop (not a tunnel-encap next hop), and the two-primary route forms an
unordered ECMP group of both local IP next hops.

Uses the existing createL3Interface / addNeighbor / setVnetRoutePriority /
updateMonitorSessionState / checkVnetLocalRoute / checkEndpointIsLocal
helpers; no new fixture infrastructure. Full VNetOrchTest 33/33, full mock
suite 945/945.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
…te (34,35,36)

Add mock equivalents of test_vnet_orch_34/35/36, the custom_bfd priority
route scenarios:

  * VnetCustomBfdPriorityRouteRepairing (34): primary/secondary re-pair
    that swaps the remote secondary and promotes a new primary.
  * VnetCustomBfdMonitorRepairSameNpu (35): the monitor IP paired with a
    remote endpoint is re-pointed several times while the endpoint set is
    unchanged; each re-pair tears down the old BFD session and creates one
    for the new monitor.
  * VnetCustomBfdPinnedMonitorState (36): a monitor's pinned_state
    overrides its live BFD state (pin-down forces failover to the backup
    while BFD is up; pin-up keeps the route on the primary while BFD is
    down).

custom_bfd routes react to BFD state ONLY through STATE_DB
BFD_SESSION_TABLE: VNetRouteOrch::updateVnetTunnel (the SAI-notification
observer) explicitly skips custom_bfd sessions, and BfdMonitorOrch instead
consumes the STATE_DB row gBfdOrch writes and drives updateCustomBfdState.
The fixture had no BfdMonitorOrch, so a bfd_session_state_change alone
never activated these routes. Wire a BfdMonitorOrch (STATE_DB
BFD_SESSION_TABLE) into the fixture and drive it after every BFD
notification; for plain-BFD routes it has no monitor_info_ entry and is a
harmless no-op.

Extend setVnetRoutePriority with optional rx/tx monitor timers and a
pinned_state trailing param so the custom_bfd routes can be programmed
with the same fields the VS create_vnet_routes uses.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
…stom_bfd (32)

Port test_vnet_orch_32 to VNetOrchTest.VnetCustomBfdPriorityRouteTwoPrimaryTwoSecondary:
a custom_bfd priority route with two remote primary and two directly-connected
local secondary endpoints. Exercises the full failover cascade -- primaries
preferred whenever any is up, fall back to the local secondary group only when
both primaries are down, withdrawn entirely when all four are down, then
restored primary-first as monitors return -- and verifies that secondary
monitor churn never disturbs an active-primary route. The /24 adv_prefix
summary is advertised whenever the route is active.

No new fixture infra: reuses createL3Interface/addNeighbor for the local
endpoints, setVnetRoutePriority (rx/tx timers), updateBfdSessionState (drives
BfdMonitorOrch for custom_bfd), checkPriorityRoute/checkStateDbRoute/
checkRouteAdvertised.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Port test_vnet_orch_26 and test_vnet_orch_27 to VNetOrchTest, covering
the MP2MP IPINIP subnet-decap term that VNetRouteOrch programs for a
BFD-monitored ECMP route on a subnet-decap-enabled switch.

The decap term is tied to the route's ACTIVE/INACTIVE state: it is
created when the route first becomes active (first monitor up) via
VNetRouteOrch::createSubnetDecapTerm, and removed when the route goes
inactive (all monitors down) or is deleted. Test 26 covers the IPv4
case; test 27 the IPv6 counterpart (term source subnet taken from the
SUBNET_DECAP src_ip_v6).

Fixture infrastructure added (reusable):
- syncTunnelDecapTerm(): diffs APP_TUNNEL_DECAP_TERM_TABLE and delivers
  VNetRouteOrch's producer writes to gTunneldecapOrch, modeled on
  syncBfd(); wired into the monitored-route set/del and BFD-state-change
  drive paths. No-op when subnet decap is disabled.
- setSubnetDecapConfig()/createSubnetDecapTunnel()/delSubnetDecapTunnel():
  drive the CFG_SUBNET_DECAP + APP_TUNNEL_DECAP_TABLE config through
  gTunneldecapOrch (mock equivalents of the setup_subnet_decap fixture +
  vnet_lib.create/delete_subnet_decap_tunnel).
- checkIpinipTunnel()/checkIpinipDecapTerm()/checkNoIpinipDecapTerm()/
  checkIpinipDecapTermRemoved(): capture and assert the IPINIP tunnel's
  decap DSCP/ECN/TTL modes and the MP2MP term's VR, action tunnel, and
  src/dst network+mask (mock equivalents of vnet_lib.check_ipinip_tunnel /
  check_ipinip_tunnel_decap_term / check_del_ipinip_tunnel_decap_term).

Extends the captured Tunnel struct with decap dscp/ecn/ttl modes and the
Term struct with dst mask + src network/mask.

Full VNetOrchTest 39/39; full mock suite 951/951.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Port test_vnet_vxlan_multi_map (test 6) to VNetOrchTest.VnetVxlanMultiMap.
On a tunnel a VNET has already bound (and thus activated), an explicit
VXLAN_TUNNEL_MAP entry adds a further VLAN<->VNI decap tunnel-map entry on
top of the VNET's VR<->VNI maps -- the "multi map" case. The mock builds a
VxlanTunnelMapOrch on APP_DB VXLAN_TUNNEL_MAP_TABLE (gVxlanTunnelMapOrch
equivalent, registered in gDirectory like orchdaemon), brings up Vlan1000
so getVlanByVlanId() resolves, and asserts the third tunnel-map entry is a
VNI_TO_VLAN_ID map (vni 1000 -> vlan 1000) against the tunnel's VNI->VLAN
decap map, leaving the VNET's two VR<->VNI entries untouched.

The VS test asserts only the VNET/tunnel entries and that adding the map
does not disturb them (it stops after delete_vnet + delete_vxlan_tunnel,
checking nothing on teardown). The mock is a faithful superset: it also
asserts the explicit entry's vni/vlan, and -- because the explicit map
holds a reference that blocks tunnel teardown -- deletes the map before the
tunnel so the full teardown (tunnel + 4 maps + P2MP term + 3 map entries)
can be verified.

Adds createVlan / createVxlanTunnelMap / delVxlanTunnelMap helpers and
captures the VLAN_ID key/value slots on tunnel-map entries.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
…(24)

Add VnetDuplicateRouteHandledGracefully, the mock equivalent of
test_vnet_orch_24 (the duplicate-route regression from commit 6e25014,
"Handle duplicate routes in a graceful manner").

A default-scope VNET programs a tunnel route for 100.100.1.0/24 directly
in the default virtual router (gVirtualRouterId). A regular route for the
same prefix -- normally learned via FRR/BGP and delivered by fpmsyncd,
here substituted as a direct APP_DB ROUTE_TABLE write (that netlink to
APP_DB translation is covered by test_route + tests_fpmsyncd) -- then
drives gRouteOrch, which is unaware of the VNET route and tries to
program the same prefix in the same VR. libsaivs returns
SAI_STATUS_ITEM_ALREADY_EXISTS for that bulk create, and
handleSaiCreateStatus must treat it as success rather than recording a
SAI failure.

The VS test asserts this via check_syslog for the ABSENCE of the failure
message; the mock equivalent is getSaiFailureStatus() staying false after
both the create and the remove phases. The captured per-entry bulk status
proves the conflicting create really hit a duplicate, and the surviving
route entry is the check_route_entries equivalent. Verified the gate is
strong: temporarily routing ITEM_ALREADY_EXISTS through handleSaiFailure
makes the test fail as expected.

Adds setRoute/delRoute helpers (regular gRouteOrch route via APP_DB
ROUTE_TABLE + DEL_COMMAND withdraw) and a lastBulkCreateStatuses capture
on RouteCaptures. Full VNetOrchTest 41/41; full mock suite 953/953.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
The 37 migrated test_vnet.py methods are now covered by the C++/gtest
mock tests in tests/mock_tests/vnetorch_ut.cpp (41 TEST_Fs). Remove them
from the VS suite so their coverage isn't duplicated and the Docker-based
VS CI runtime is reclaimed.

test_vnet_orch_4 is intentionally RETAINED: it is @pytest.mark.skip
("Failing. Under investigation") in the VS suite and its VNET peering
behaviour (cross-VRF route replication via peer_list) has no mock
equivalent, so it was not migrated. Per policy, un-migrated cases are not
deleted. The class scaffolding it depends on is kept with it, and the
module-level test_nonflaky_dummy remains so the module still has an active
test.

vnet_lib.py is likewise kept (imported by test_vnet2.py and orch_4).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
…eering

Two coverage-fidelity fixes to the VNET mock tests, both matching what the
original test_vnet.py actually exercised:

1. Route CONFIG->APP path. The VS create_vnet_routes / create_vnet_local_
   routes write CONFIG_DB VNET_ROUTE_TUNNEL / VNET_ROUTE and rely on
   VNetCfgRouteOrch to mirror them to the APP_DB tables VNetRouteOrch
   consumes. The mock wrote APP_DB directly, bypassing
   VNetCfgRouteOrch::doVnetTunnelRouteTask / doVnetRouteTask. Add
   VNetCfgRouteOrch to the fixture (as orchdaemon does) and route every SET
   helper (setVnetRoute, setVnetRouteMonitored, setVnetRoutePriority,
   setVnetLocalRoute) through CONFIG_DB via a new programVnetRouteViaCfg(),
   so the real CONFIG->APP translation runs. Deletes still go to APP_DB,
   matching the VS delete_vnet_routes.

2. VNET peering -- migrates test_vnet_orch_4 (which is @pytest.mark.skip in
   the VS suite, so this restores real coverage rather than duplicating a
   live test). VnetPeeringReplicatesRouteIntoPeerVr: two VNETs peer via
   peer_list, and a tunnel route created in one is programmed in BOTH its
   own VR and the peer's VR (VNetRouteOrch::doRouteTask builds vr_set over
   vnet + peer_list), the check_vnet_routes(peer) assertion the VS test made.

Full VNetOrchTest 42/42; full mock suite 974/974. VNetOrchTest is stable
across 20 shuffled in-process repeats.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
…MP test

All 38 originally-migrated test_vnet.py methods (incl. orch_4 peering, now
covered by VnetPeeringReplicatesRouteIntoPeerVr) are removed. The one method
kept is test_vnet_local_route_ecmp_unnumbered -- added on master after this
branch was cut and not yet migrated, so per policy it stays in the VS module
rather than being deleted. tests/vnet_lib.py is likewise kept (test_vnet2.py
imports it).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
Migrate test_vnet_local_route_ecmp_unnumbered (added on master) as
VnetLocalRouteUnnumberedEcmp. A VNET local ECMP route whose members share
ONE link-local next-hop IP reached via two interfaces: master's
VNetRouteOrch parses `nexthop` as an ordered ip/ifname list (duplicate IPs
preserved) instead of a deduped IpAddresses set, so 169.254.0.1 listed
twice with different ifnames yields a 2-member NHG on distinct RIFs. The
test walks all five VS phases: 2-member NHG on distinct RIFs (A); shrink to
a single IP next hop on one RIF (B); regrow (C); oper-down one port so its
member is pruned (D); bring it back up + re-learn the neighbor so the group
reforms (E). Because the IP is shared, membership is asserted by RIF
(captured from SAI_NEXT_HOP_ATTR_ROUTER_INTERFACE_ID), mirroring the VS
_nhgm_rifs()/_nh_rif() checks.

Fixture: build gMlagOrch (as orchdaemon does) -- FdbOrch observes port
oper-status changes and calls gMlagOrch->isMlagInterface() on a DOWN, so a
null gMlagOrch segfaults the port-down phase (fdborch.cpp:1722).

Full VNetOrchTest 43/43; full mock suite 982/982; stable across 20 shuffled
in-process repeats.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
test_vnet_local_route_ecmp_unnumbered is now covered by
VnetLocalRouteUnnumberedEcmp, so the last remaining VS method is migrated
and tests/test_vnet.py is deleted in full. tests/vnet_lib.py is kept --
test_vnet2.py imports it.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b820490a-c3c2-490a-96de-a1fcfc233510
Signed-off-by: Lawrence Lee <lawlee@microsoft.com>
@theasianpianist
theasianpianist force-pushed the migrate-test-vnet-to-mock branch from a43f459 to 35d0437 Compare August 5, 2026 18:30
Copilot AI review requested due to automatic review settings August 5, 2026 18:30
@mssonicbld

Copy link
Copy Markdown
Collaborator

/azp run

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 1 pipeline(s).

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 8 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants