"""Pruebas del simulador de vector de caminos (spvp.py). No levantan ninguna red."""
import random
import unittest

import spvp


class ValleyFree(unittest.TestCase):
    def setUp(self):
        self.graph = spvp.ases_graph()

    def test_up_peer_down_is_valley_free(self):
        # r1 -> r2 -> r5 -> r6 -> r3: sube, sube, peer, baja.
        self.assertTrue(spvp.is_valley_free(self.graph, [64601, 64602, 64605, 64606, 64603]))

    def test_provider_through_customer_is_a_valley(self):
        # r2 -> r1 -> r4: r1 le da tránsito gratis a sus dos proveedores.
        self.assertFalse(spvp.is_valley_free(self.graph, [64602, 64601, 64604]))

    def test_up_after_a_peer_link_is_not_valley_free(self):
        # 3 es peer de 2, y 2 es cliente de 1. Que 2 le pase a su proveedor una ruta de su
        # peer, o a su peer una ruta de su proveedor, es lo que prohíbe la exportación.
        graph = spvp.Graph({1: [], 2: [1], 3: []}, [(2, 3)])
        self.assertFalse(spvp.is_valley_free(graph, [1, 2, 3]))
        self.assertFalse(spvp.is_valley_free(graph, [3, 2, 1]))
        self.assertTrue(spvp.is_valley_free(graph, [3, 2]))

    def test_two_peer_links_are_not_valley_free(self):
        graph = spvp.Graph({1: [], 2: [], 3: []}, [(1, 2), (2, 3)])
        self.assertFalse(spvp.is_valley_free(graph, [1, 2, 3]))

    def test_unknown_link_is_rejected(self):
        self.assertFalse(spvp.is_valley_free(self.graph, [64603, 64605]))


class Convergence(unittest.TestCase):
    def test_provider_cycle_with_free_ranking_never_settles(self):
        graph = spvp.ring_graph(cycle=True)
        stable, _, _ = spvp.simulate(graph, 0, spvp.ring_rank, spvp.gao_rexford_export, [1, 2, 3])
        self.assertFalse(stable)

    def test_same_ranking_without_cycle_settles_in_any_order(self):
        graph = spvp.ring_graph(cycle=False)
        for seed in range(30):
            order = [1, 2, 3]
            random.Random(seed).shuffle(order)
            stable, best, _ = spvp.simulate(graph, 0, spvp.ring_rank,
                                            spvp.gao_rexford_export, order)
            self.assertTrue(stable, order)
            self.assertEqual(best[3], (3, 0))

    def test_six_ases_settle_on_valley_free_paths(self):
        graph = spvp.ases_graph()
        for destination in graph.nodes:
            best = spvp.predicted_paths(destination)
            for node in graph.nodes:
                self.assertIsNotNone(best[node], (node, destination))
                self.assertTrue(spvp.is_valley_free(graph, list(best[node])))

    def test_the_final_state_does_not_depend_on_the_order(self):
        graph = spvp.ases_graph()
        others = [node for node in graph.nodes if node != 64603]
        results = set()
        for seed in range(30):
            order = others[:]
            random.Random(seed).shuffle(order)
            stable, best, _ = spvp.simulate(graph, 64603, spvp.gao_rexford_rank,
                                            spvp.gao_rexford_export, order)
            self.assertTrue(stable)
            results.add(tuple(sorted(best.items())))
        self.assertEqual(len(results), 1)


if __name__ == "__main__":
    unittest.main()
