#!/usr/bin/env python
# -*- coding: utf-8 eval: (blacken-mode 1) -*-
# SPDX-License-Identifier: ISC
#
# test_rip_no_neighbor.py:
# RIP No Neighbor Test
#
# Copyright (c) 2025 by Dustin Rosarius
#

r"""
test_rip_no_neighbor.py: Test to verify that disabling a rip neighbor via the "no neighbor" command works correctly.
"""

import os
import sys
import pytest
import json
import functools

# Import topogen and required test moduless
CWD = os.path.dirname(os.path.realpath(__file__))
sys.path.append(os.path.join(CWD, "../"))

from lib import topotest
from lib.topogen import Topogen, TopoRouter
from lib.common_config import step

pytestmark = [pytest.mark.ripd, pytest.mark.staticd]


def build_topo(tgen):
    """Build the topology for RIP no neighbor test."""

    # Create router
    r1 = tgen.add_router("r1")
    r2 = tgen.add_router("r2")

    tgen.add_link(r1, r2)


@pytest.fixture(scope="module")
def tgen(request):
    "Setup/Teardown the environment and provide tgen argument to tests"

    tgen = Topogen(build_topo, request.module.__name__)
    tgen.start_topology()

    router_list = tgen.routers()

    # For all routers arrange for:
    # - starting zebra using config file from <rtrname>/zebra.conf
    # - starting ripd using an empty config file.
    # - loading frr config file from <rtrname>/frr.conf
    for rname, router in router_list.items():
        router.load_config(TopoRouter.RD_ZEBRA)
        router.load_config(TopoRouter.RD_RIP)
        router.load_config(TopoRouter.RD_STATIC)
        router.load_frr_config(os.path.join(CWD, f"{rname}/frr.conf"))

    # Start and configure the router daemons
    tgen.start_router()

    # Provide tgen as argument to each test function
    yield tgen

    # Teardown after last test runs
    tgen.stop_topology()


# ===================
# The tests functions
# ===================


def test_rip_no_neighbor(tgen):

    r1 = tgen.gears["r1"]
    r2 = tgen.gears["r2"]

    def _show_route(router, expected, exact=False):
        output = json.loads(router.vtysh_cmd("sh ip route 192.168.105.0/24 json"))

        return topotest.json_cmp(output, expected, exact=exact)

    step("verify r1 has 192.168.105.0/24 in routing table as a rip route")

    expected = {
        "192.168.105.0/24": [
            {
                "protocol": "rip",
            }
        ]
    }
    test_func = functools.partial(_show_route, r1, expected)
    _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)

    assert result is None, "Route 192.168.105.0/24 is not present in r1 routing table"

    step("Disable neighbor on r2")
    r2.vtysh_cmd(
        """
        configure terminal
        router rip
        no neighbor 10.1.12.1
        exit
        """
    )

    step("Verify r1 does not have 192.168.105.0/24 in routing table")
    expected = {}
    test_func = functools.partial(_show_route, r1, expected, True)
    _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)

    assert result is None, "Route 192.168.105.0/24 is still present in r1 routing table"

    step("reenable neighbor on r2")
    r2.vtysh_cmd(
        """
        configure terminal
        router rip
        neighbor 10.1.12.1
        exit
        """
    )
    step("verify r1 has 192.168.105.0/24 in routing table as a rip route")

    expected = {
        "192.168.105.0/24": [
            {
                "protocol": "rip",
            }
        ]
    }
    test_func = functools.partial(_show_route, r1, expected)
    _, result = topotest.run_and_expect(test_func, None, count=60, wait=1)

    assert result is None, "Route 192.168.105.0/24 is not present in r1 routing table"


if __name__ == "__main__":
    args = ["-s"] + sys.argv[1:]
    sys.exit(pytest.main(args))
