Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 12 additions & 4 deletions rig/routing_table/ordered_covering.py
Original file line number Diff line number Diff line change
Expand Up @@ -180,11 +180,12 @@ def minimise(routing_table, target_length):
[:py:class:`~rig.routing_table.RoutingTableEntry`, ...]
Reduced routing table entries.
"""
table, _ = ordered_covering(routing_table, target_length)
table, _ = ordered_covering(routing_table, target_length, no_raise=True)
return remove_default_routes(table, target_length)


def ordered_covering(routing_table, target_length, aliases=dict()):
def ordered_covering(routing_table, target_length, aliases=dict(),
no_raise=False):
"""Reduce the size of a routing table by merging together entries where
possible.

Expand Down Expand Up @@ -232,12 +233,17 @@ def ordered_covering(routing_table, target_length, aliases=dict()):
determining if inserting a new entry will break the correctness of the
table. This should be supplied when using this method to update an
already minimised table.
no_raise : bool
If False (the default) then an error will be raised if the table cannot
be minimised to be smaller than `target_length` and `target_length` is
not None. If True then a table will be returned regardless of the size
of the final table.

Raises
------
MinimisationFailedError
If the smallest table that can be produced is larger than
`target_length`.
`target_length` and `no_raise` is False.

Returns
-------
Expand Down Expand Up @@ -269,7 +275,9 @@ def ordered_covering(routing_table, target_length, aliases=dict()):
routing_table, aliases = merge.apply(aliases)

# If the table is still too big then raise an error
if target_length is not None and len(routing_table) > target_length:
if (not no_raise and
target_length is not None and
len(routing_table) > target_length):
raise MinimisationFailedError(target_length, len(routing_table))

# Return the finished routing table and aliases table
Expand Down
42 changes: 42 additions & 0 deletions tests/routing_table/test_routing_table_ordered_covering.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,26 @@ def test_also_removes_default_routes(self):
RTE({Routes.north}, 0b0000, 0xe, {Routes.west}),
]

def test_must_removes_default_routes(self):
"""Attempt to minimise the following table.

W -> 0000 -> E
E -> 0001 -> W
N -> 1000 -> S

The result should be an empty table: BUT, entries can only be removed
by using default routing and the minimum table size will cause ordered
covering to fail.
"""
RTE = RoutingTableEntry
table = [
RTE({Routes.east}, 0b0000, 0xf, {Routes.west}),
RTE({Routes.west}, 0b0001, 0xf, {Routes.east}),
RTE({Routes.south}, 0b1000, 0xf, {Routes.north}),
]

assert len(minimise(table, target_length=2)) == 0


def test_ordered_covering_simple():
"""Test that a very simple routing table can be minimised, only one
Expand Down Expand Up @@ -441,3 +461,25 @@ def test_ordered_covering_simple():
(0b0010, 0b1110): {(0b0010, 0b1111), (0b0011, 0b1111)},
(0b0000, 0b1110): {(0b0000, 0b1111), (0b0001, 0b1111)},
}


def test_ordered_covering_simple_fails_if_too_large():
"""Test that a very simple routing table can be minimised, and that an
exception is raised if that minimisation is still too large.

Table::

0000 -> N, NE
0001 -> N, NE
001X -> S
"""
# Original table
RTE = RoutingTableEntry
table = [
RTE({Routes.north, Routes.north_east}, 0b0000, 0b1111),
RTE({Routes.north, Routes.north_east}, 0b0001, 0b1111),
RTE({Routes.south}, 0b0010, 0b1110),
]

with pytest.raises(MinimisationFailedError):
ordered_covering(table, target_length=1)