def test_e2_replace_br_is_not_nbr(self): # Advertise a route that replaces the best route but does not become # the new best route self.tracker_worker.new_best_route = mock.Mock( side_effect=self._call_list(t.NBR)) self.tracker_worker.best_route_removed = mock.Mock( side_effect=self._call_list(t.BRR)) # 2 sources : A and B worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') worker_b = worker.Worker(mock.Mock(), 'worker.Worker-B') # Source A advertises a route1 for NLRI1 self._append_call("RE1") route1_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 300) # Source B advertises a route2. Route1 is better than Route2 self._append_call("RE2") route2_nrli1b = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 200) # Source A advertises a route3 for NLRI1. Route3 replaces Route1. # Route2 is better than route3. self._append_call("RE3") route3_nrli1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100, route1_nlri1a.route_entry) # Source B withdraws route2 for NLRI1 self._append_call("RE4") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 200) # Check calls and arguments list to new_best_route and # best_route_removed expected_calls = [ "RE1", t.NBR, "RE2", "RE3", t.NBR, t.BRR, "RE4", t.NBR, t.BRR ] self.assertEqual(expected_calls, self._calls, 'Wrong call sequence') self.assertEqual(3, self.tracker_worker.new_best_route.call_count, '3 new new_best_route calls for NLRI1') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry), (t.NLRI1, route2_nrli1b.route_entry), (t.NLRI1, route3_nrli1a.route_entry)]) self.assertEqual(2, self.tracker_worker.best_route_removed.call_count, '2 best_route_removed calls for NLRI1') self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry, False), (t.NLRI1, route2_nrli1b.route_entry, False)])
def test_e5_replace_br_is_nbr_equal(self): # Same as E3, but the route that replaces our current best compares # equally to the two initially less preferred routes, and becomes best # route with them self.tracker_worker.new_best_route = mock.Mock( side_effect=self._call_list(t.NBR)) self.tracker_worker.best_route_removed = mock.Mock( side_effect=self._call_list(t.BRR)) # 3 sources: A, B and C worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') worker_b = worker.Worker(mock.Mock(), 'worker.Worker-B') worker_c = worker.Worker(mock.Mock(), 'worker.Worker-C') # Source A advertises route1 for NLRI1 route1 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 300) # We will only check events after this first one # to allow for a order-independent test after RE4 del self.tracker_worker.new_best_route.call_args_list[:] # Source B advertises route2 for NLRI1 : route1 is better than route2 self._append_call("RE2") route2 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 200) # Source C advertises also route2 self._append_call("RE3") route3 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_c, t.NH2, 200) # Source A advertises route3 which replaces route1 self._append_call("RE4") route4 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH3, 200, route1.route_entry) # Check calls and arguments list to new_best_route and # best_route_removed expected_calls = [ t.NBR, "RE2", "RE3", "RE4", t.NBR, t.NBR, t.NBR, t.BRR ] self.assertEqual(expected_calls, self._calls, 'Wrong call sequence') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route2.route_entry), (t.NLRI1, route3.route_entry), (t.NLRI1, route4.route_entry)], False) self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route1.route_entry, False)])
def test_c1_route1_best_route(self): # Route1 is the best route # Mock objects self.tracker_worker.new_best_route = mock.Mock( side_effect=self._call_list(t.NBR)) self.tracker_worker.best_route_removed = mock.Mock( side_effect=self._call_list(t.BRR)) # 2 sources : A and B worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') worker_b = worker.Worker(mock.Mock(), 'worker.Worker-B') # Source A advertises a route1 for NLRI1 self._append_call("RE1") route1_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 300) # Source B advertises a route2 for NLRI1 with different attributes. # Route1 is better than Route2 self._append_call("RE2") route2_nlri1b = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 200) # Source A withdraws route1 for NLRI1 self._append_call("RE3") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 300) # Source B withdraws route2 for NLRI1 self._append_call("RE4") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 200) # Check calls and arguments list to new_best_route and # best_route_removed expected_calls = [ "RE1", t.NBR, "RE2", "RE3", t.NBR, t.BRR, "RE4", t.BRR ] self.assertEqual(expected_calls, self._calls, 'Wrong call sequence') self.assertEqual(2, self.tracker_worker.new_best_route.call_count, '2 new new_best_route calls for NLRI1') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry), (t.NLRI1, route2_nlri1b.route_entry)]) self.assertEqual(2, self.tracker_worker.best_route_removed.call_count, '2 best_route_removed calls for NLRI1') self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry, False), (t.NLRI1, route2_nlri1b.route_entry, True)])
def test_e3_replace_br_is_not_nbr(self): # Advertise a route that replaces the best route but does not become # the new best route self.tracker_worker.new_best_route = mock.Mock( side_effect=self._call_list(t.NBR)) self.tracker_worker.best_route_removed = mock.Mock( side_effect=self._call_list(t.BRR)) # 3 sources: A, B and C worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') worker_b = worker.Worker(mock.Mock(), 'worker.Worker-B') worker_c = worker.Worker(mock.Mock(), 'worker.Worker-C') # Source A advertises route1 for NLRI1 self._append_call("RE1") route1_nlri1 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 300) # Source B advertises route2 for NLRI1 : route1 is better than route2 self._append_call("RE2") route2_nlri1 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 200) # Source C advertises also route2 self._append_call("RE3") self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_c, t.NH1, 200) # Source A advertises route3 which replaces route1 self._append_call("RE4") self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100, route1_nlri1.route_entry) # Check calls and arguments list to new_best_route and # best_route_removed expected_calls = ["RE1", t.NBR, "RE2", "RE3", "RE4", t.NBR, t.BRR] self.assertEqual(expected_calls, self._calls, 'Wrong call sequence') self.assertEqual(2, self.tracker_worker.new_best_route.call_count, '2 new best route call for NLRI1') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route1_nlri1.route_entry), (t.NLRI1, route2_nlri1.route_entry)]) self.assertEqual(1, self.tracker_worker.best_route_removed.call_count, '1 best_route_removed call for NLRI1') self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route1_nlri1.route_entry)])
def test_b2_is_not_the_current_best_route(self): # The route which is advertised by an other source is not the current # best route but will become the best route self.tracker_worker.new_best_route = mock.Mock( side_effect=self._call_list(t.NBR)) self.tracker_worker.best_route_removed = mock.Mock( side_effect=self._call_list(t.BRR)) # 3 sources: A, B and C worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') worker_b = worker.Worker(mock.Mock(), 'worker.Worker-B') worker_c = worker.Worker(mock.Mock(), 'worker.Worker-C') # Source A advertises route1 for NLRI1 self._append_call("RE1") route1Nlri1 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 300) # Source B advertises route2 for NLRI1 : route1 is better than route2 self._append_call("RE2") route2Nlri1 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 200) # Source C advertises also route2 self._append_call("RE3") self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_c, t.NH1, 200) # Source A withdraws route1 self._append_call("RE4") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 300) # Check calls and arguments list to new_best_route and # best_route_removed expected_calls = ["RE1", t.NBR, "RE2", "RE3", "RE4", t.NBR, t.BRR] self.assertEqual(expected_calls, self._calls, 'Wrong call sequence') self.assertEqual(2, self.tracker_worker.new_best_route.call_count, '2 new best route call for NLRI1') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route1Nlri1.route_entry), (t.NLRI1, route2Nlri1.route_entry)]) self.assertEqual(1, self.tracker_worker.best_route_removed.call_count, '1 best_route_removed call for NLRI1') self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route1Nlri1.route_entry, False)])
def test_b1_is_the_current_best_route(self): # The route which is advertised by another source is the current best # route self.tracker_worker.new_best_route = mock.Mock( side_effect=self._call_list(t.NBR)) self.tracker_worker.best_route_removed = mock.Mock( side_effect=self._call_list(t.BRR)) # 2 sources: A and B worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') worker_b = worker.Worker(mock.Mock(), 'worker.Worker-B') # Source A advertises a route for NLRI1 self._append_call("RE1") route_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source B advertises the same route for NLRI1 self._append_call("RE2") route_nlri1B = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 100) # Source A withdraws the route for NLRI1 self._append_call("RE3") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source B withdraws the route for NLRI1 self._append_call("RE4") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 100) # Check calls and arguments list to new_best_route and # best_route_removed self.assertEqual(1, self.tracker_worker.new_best_route.call_count, '1 new best route call for NLRI1') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route_nlri1a.route_entry)]) self.assertEqual(1, self.tracker_worker.best_route_removed.call_count, '1 best_route_removed call for NLRI1') self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route_nlri1B.route_entry, True)]) expected_calls = ["RE1", t.NBR, "RE2", "RE3", "RE4", t.BRR] self.assertEqual(expected_calls, self._calls, 'Wrong call sequence')
def test_a2_different_nlri_different_source(self): # 2 sources A and B advertise and withdraw routes for different NLRI. # Mock objects self.tracker_worker.new_best_route = mock.Mock() self.tracker_worker.best_route_removed = mock.Mock() # 2 sources: A and B worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') worker_b = worker.Worker(mock.Mock(), 'worker.Worker-B') # Source A advertises a route for NLRI1 route_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source B advertises a route for NLRI2 route_nlri2B = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI2, [t.RT1, t.RT2], worker_b, t.NH1, 100) # Source A withdraws the route for NLRI1 self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source B withdraws the route for NLRI2 self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI2, [t.RT1, t.RT2], worker_b, t.NH1, 100) # Check calls and arguments list to new_best_route and # best_route_removed self.assertEqual( 2, self.tracker_worker.new_best_route.call_count, '2 new_best_route calls: 1 for NLRI1 and 1 for NLRI2') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route_nlri1a.route_entry), (t.NLRI2, route_nlri2B.route_entry)]) self.assertEqual( 2, self.tracker_worker.best_route_removed.call_count, '2 best_route_removed calls: 1 for NLRI1 and 1 for ' 'NLRI2') self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route_nlri1a.route_entry, True), (t.NLRI2, route_nlri2B.route_entry, True)])
def test_d1_ecmp_routes(self): # ECMP routes are routes advertised by the same worker with the same # LP and different NH self.tracker_worker.new_best_route = mock.Mock( side_effect=self._call_list(t.NBR)) self.tracker_worker.best_route_removed = mock.Mock( side_effect=self._call_list(t.BRR)) # 1 source: A worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') # Source A advertises a route1 for NLRI1 self._append_call("RE1") route1_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source A advertises a route2 for NLRI1. route2 is equal to route1 # with compare_routes, but the next_hop are different self._append_call("RE2") route2_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH2, 100) # Source A withdraws route1 for NLRI1 self._append_call("RE3") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source A withdraws route2 for NLRI1 self._append_call("RE4") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH2, 100) # Check calls and arguments list to new_best_route and # best_route_removed expected_calls = [ "RE1", t.NBR, "RE2", t.NBR, "RE3", t.BRR, "RE4", t.BRR ] self.assertEqual(expected_calls, self._calls, 'Wrong call sequence') self.assertEqual(2, self.tracker_worker.new_best_route.call_count, '2 new new_best_route calls for NLRI1') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry), (t.NLRI1, route2_nlri1a.route_entry)]) self.assertEqual(2, self.tracker_worker.best_route_removed.call_count, '2 best_route_removed calls for NLRI1') self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry, False), (t.NLRI1, route2_nlri1a.route_entry, True)])
def test_a4_withdraw_nlri_not_known(self): # A source A withdraws a route that does not exist. self.tracker_worker.new_best_route = mock.Mock() self.tracker_worker.best_route_removed = mock.Mock() # 1 source: A worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') # Source A withdraws a route for NLRI1 which is not known by # tracker_worker self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Check calls to new_best_route and best_route_removed self.assertEqual(0, self.tracker_worker.new_best_route.call_count, 'new_best_route should not have been called') self.assertEqual(0, self.tracker_worker.best_route_removed.call_count, 'best_route_removed should not have been called')
def test_max_lp_is_best(self): worker_a = worker.Worker(mock.Mock(), 'worker') route_lp55 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 55).route_entry route_lp45 = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 45).route_entry self.assertTrue( tracker_worker.compare_ecmp(mock.Mock(), route_lp55, route_lp45) > 0) self.assertTrue( tracker_worker.compare_no_ecmp(mock.Mock(), route_lp55, route_lp45) > 0)
def test_e1_replace_br_is_nbr(self): # Advertise a route that replaces the best route and becomes the new # best route self.tracker_worker.new_best_route = mock.Mock( side_effect=self._call_list(t.NBR)) self.tracker_worker.best_route_removed = mock.Mock( side_effect=self._call_list(t.BRR)) # 1 source: A worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') # Source A advertises a route1 for NLRI1 self._append_call("RE1") route1_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 200) # Source A advertises a route2 for NLRI1. Route1 is better than Route2 # BUT Route2 replaces Route1 self._append_call("RE2") route2_nrli1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100, route1_nlri1a.route_entry) # Check calls and arguments list to new_best_route and # best_route_removed expected_calls = ["RE1", t.NBR, "RE2", t.NBR, t.BRR] self.assertEqual(expected_calls, self._calls, 'Wrong call sequence') self.assertEqual(2, self.tracker_worker.new_best_route.call_count, '2 new new_best_route calls for NLRI1') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry), (t.NLRI1, route2_nrli1a.route_entry)]) self.assertEqual(1, self.tracker_worker.best_route_removed.call_count, '1 best_route_removed call for NLRI1') self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry, False)])
def test_a3_same_nlri_same_source(self): # A source A advertises the same route for the same NLRI # Mock objects self.tracker_worker.new_best_route = mock.Mock() self.tracker_worker.best_route_removed = mock.Mock() # 1 source: A worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') # Source A advertises a route for NLRI1 route_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source A advertises the same route for NLRI1 self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Check calls and arguments list to new_best_route and # best_route_removed self.assertEqual(1, self.tracker_worker.new_best_route.call_count, 'expected 1 new_best_route call for NLRI1') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route_nlri1a.route_entry), (t.NLRI1, route_nlri1a.route_entry)])
def test_a1_different_nlri_same_source(self): # A source A advertises and withdraws routes for different NLRI. # Mock objects self.tracker_worker._new_best_route = mock.Mock() self.tracker_worker._best_route_removed = mock.Mock() # Only 1 source A worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') # Source A advertises a route for NLRI1 route_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source A advertises a route for NLRI2 route_nlri2a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI2, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source A withdraws the route for NLRI1 self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Source A withdraws the route for NLRI2 self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI2, [t.RT1, t.RT2], worker_a, t.NH1, 100) # Check calls and arguments list to _new_best_route and # _best_route_removed self.assertEqual(2, self.tracker_worker._new_best_route.call_count, '2 new best routes: 1 for NLRI1 and 1 for NLRI2') self._check_calls(self.tracker_worker._new_best_route.call_args_list, [(t.NLRI1, route_nlri1a.route_entry), (t.NLRI2, route_nlri2a.route_entry)]) self.assertEqual(2, self.tracker_worker._best_route_removed.call_count, '2 old routes removed: 1 for NLRI1 and 1 for NLRI2') self._check_calls( self.tracker_worker._best_route_removed.call_args_list, [(t.NLRI1, route_nlri1a.route_entry, True), (t.NLRI2, route_nlri2a.route_entry, True)])
def test_c3_select_new_best_route_among_several(self): # When current best route is withdrawn, the new best route should be # selected among several routes self.tracker_worker.new_best_route = mock.Mock( side_effect=self._call_list(t.NBR)) self.tracker_worker.best_route_removed = mock.Mock( side_effect=self._call_list(t.BRR)) # 3 sources: A, B and C worker_a = worker.Worker(mock.Mock(), 'worker.Worker-A') worker_b = worker.Worker(mock.Mock(), 'worker.Worker-B') worker_c = worker.Worker(mock.Mock(), 'worker.Worker-C') # Source A advertises a route1 for NLRI1 self._append_call("RE1") route1_nlri1a = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 300) # Source B advertises a route2 for NLRI1. Route1 is better than Route2 self._append_call("RE2") route2_nlri1b = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 200) # Source C advertises a route3 for NLRI1. Route2 is better than Route3 self._append_call("RE3") route3_nlri1c = self._new_route_event(engine.RouteEvent.ADVERTISE, t.NLRI1, [t.RT1, t.RT2], worker_c, t.NH1, 100) # Source A withdraws route1 for NLRI1 self._append_call("RE4") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_a, t.NH1, 300) # Source B withdraws route2 for NLRI1 self._append_call("RE5") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_b, t.NH1, 200) # Source C withdraws route3 for NLRI1 self._append_call("RE6") self._new_route_event(engine.RouteEvent.WITHDRAW, t.NLRI1, [t.RT1, t.RT2], worker_c, t.NH1, 100) # Check calls and arguments list to new_best_route and # best_route_removed expected_calls = [ "RE1", t.NBR, "RE2", "RE3", "RE4", t.NBR, t.BRR, "RE5", t.NBR, t.BRR, "RE6", t.BRR ] self.assertEqual(expected_calls, self._calls, 'Wrong call sequence') self.assertEqual(3, self.tracker_worker.new_best_route.call_count, '3 new new_best_route calls for NLRI1') self._check_calls(self.tracker_worker.new_best_route.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry), (t.NLRI1, route2_nlri1b.route_entry), (t.NLRI1, route3_nlri1c.route_entry)]) self.assertEqual(3, self.tracker_worker.best_route_removed.call_count, '3 best_route_removed calls for NLRI1') self._check_calls( self.tracker_worker.best_route_removed.call_args_list, [(t.NLRI1, route1_nlri1a.route_entry, False), (t.NLRI1, route2_nlri1b.route_entry, False), (t.NLRI1, route3_nlri1c.route_entry, True)])