180 lines
6.8 KiB
Python
180 lines
6.8 KiB
Python
|
from networkx import is_connected, neighbors
|
||
|
from networkx.generators.internet_as_graphs import random_internet_as_graph
|
||
|
from networkx.testing import almost_equal
|
||
|
|
||
|
|
||
|
class TestInternetASTopology():
|
||
|
|
||
|
@classmethod
|
||
|
def setup_class(cls):
|
||
|
cls.n = 1000
|
||
|
cls.seed = 42
|
||
|
cls.G = random_internet_as_graph(cls.n, cls.seed)
|
||
|
cls.T = []
|
||
|
cls.M = []
|
||
|
cls.C = []
|
||
|
cls.CP = []
|
||
|
cls.customers = {}
|
||
|
cls.providers = {}
|
||
|
|
||
|
for i in cls.G.nodes():
|
||
|
if cls.G.nodes[i]['type'] == 'T':
|
||
|
cls.T.append(i)
|
||
|
elif cls.G.nodes[i]['type'] == 'M':
|
||
|
cls.M.append(i)
|
||
|
elif cls.G.nodes[i]['type'] == 'C':
|
||
|
cls.C.append(i)
|
||
|
elif cls.G.nodes[i]['type'] == 'CP':
|
||
|
cls.CP.append(i)
|
||
|
else:
|
||
|
raise ValueError("Inconsistent data in the graph\
|
||
|
node attributes")
|
||
|
cls.set_customers(i)
|
||
|
cls.set_providers(i)
|
||
|
|
||
|
@classmethod
|
||
|
def set_customers(cls, i):
|
||
|
if i not in cls.customers:
|
||
|
cls.customers[i] = set()
|
||
|
for j in neighbors(cls.G, i):
|
||
|
e = cls.G.edges[(i, j)]
|
||
|
if e['type'] == 'transit':
|
||
|
customer = int(e['customer'])
|
||
|
if j == customer:
|
||
|
cls.set_customers(j)
|
||
|
cls.customers[i] = cls.customers[i].union(
|
||
|
cls.customers[j])
|
||
|
cls.customers[i].add(j)
|
||
|
elif i != customer:
|
||
|
raise ValueError("Inconsistent data in the graph\
|
||
|
edge attributes")
|
||
|
|
||
|
@classmethod
|
||
|
def set_providers(cls, i):
|
||
|
if i not in cls.providers:
|
||
|
cls.providers[i] = set()
|
||
|
for j in neighbors(cls.G, i):
|
||
|
e = cls.G.edges[(i, j)]
|
||
|
if e['type'] == 'transit':
|
||
|
customer = int(e['customer'])
|
||
|
if i == customer:
|
||
|
cls.set_providers(j)
|
||
|
cls.providers[i] = cls.providers[i].union(
|
||
|
cls.providers[j])
|
||
|
cls.providers[i].add(j)
|
||
|
elif j != customer:
|
||
|
raise ValueError("Inconsistent data in the graph\
|
||
|
edge attributes")
|
||
|
|
||
|
def test_wrong_input(self):
|
||
|
G = random_internet_as_graph(0)
|
||
|
assert len(G.nodes()) == 0
|
||
|
|
||
|
G = random_internet_as_graph(-1)
|
||
|
assert len(G.nodes()) == 0
|
||
|
|
||
|
G = random_internet_as_graph(1)
|
||
|
assert len(G.nodes()) == 1
|
||
|
|
||
|
def test_node_numbers(self):
|
||
|
assert len(self.G.nodes()) == self.n
|
||
|
assert len(self.T) < 7
|
||
|
assert len(self.M) == int(round(self.n*0.15))
|
||
|
assert len(self.CP) == int(round(self.n*0.05))
|
||
|
numb = self.n - len(self.T) - len(self.M) - len(self.CP)
|
||
|
assert len(self.C) == numb
|
||
|
|
||
|
def test_connectivity(self):
|
||
|
assert is_connected(self.G)
|
||
|
|
||
|
def test_relationships(self):
|
||
|
# T nodes are not customers of anyone
|
||
|
for i in self.T:
|
||
|
assert len(self.providers[i]) == 0
|
||
|
|
||
|
# C nodes are not providers of anyone
|
||
|
for i in self.C:
|
||
|
assert len(self.customers[i]) == 0
|
||
|
|
||
|
# CP nodes are not providers of anyone
|
||
|
for i in self.CP:
|
||
|
assert len(self.customers[i]) == 0
|
||
|
|
||
|
# test whether there is a customer-provider loop
|
||
|
for i in self.G.nodes():
|
||
|
assert len(self.customers[i].intersection(
|
||
|
self.providers[i])) == 0
|
||
|
|
||
|
# test whether there is a peering with a customer or provider
|
||
|
for i, j in self.G.edges():
|
||
|
if self.G.edges[(i, j)]['type'] == 'peer':
|
||
|
assert j not in self.customers[i]
|
||
|
assert i not in self.customers[j]
|
||
|
assert j not in self.providers[i]
|
||
|
assert i not in self.providers[j]
|
||
|
|
||
|
def test_degree_values(self):
|
||
|
d_m = 0 # multihoming degree for M nodes
|
||
|
d_cp = 0 # multihoming degree for CP nodes
|
||
|
d_c = 0 # multihoming degree for C nodes
|
||
|
p_m_m = 0 # avg number of peering edges between M and M
|
||
|
p_cp_m = 0 # avg number of peering edges between CP and M
|
||
|
p_cp_cp = 0 # avg number of peering edges between CP and CP
|
||
|
t_m = 0 # probability M's provider is T
|
||
|
t_cp = 0 # probability CP's provider is T
|
||
|
t_c = 0 # probability C's provider is T
|
||
|
|
||
|
for i, j in self.G.edges():
|
||
|
e = self.G.edges[(i, j)]
|
||
|
if e['type'] == 'transit':
|
||
|
cust = int(e['customer'])
|
||
|
if i == cust:
|
||
|
prov = j
|
||
|
elif j == cust:
|
||
|
prov = i
|
||
|
else:
|
||
|
raise ValueError("Inconsistent data in the graph edge\
|
||
|
attributes")
|
||
|
if cust in self.M:
|
||
|
d_m += 1
|
||
|
if self.G.nodes[prov]['type'] == 'T':
|
||
|
t_m += 1
|
||
|
elif cust in self.C:
|
||
|
d_c += 1
|
||
|
if self.G.nodes[prov]['type'] == 'T':
|
||
|
t_c += 1
|
||
|
elif cust in self.CP:
|
||
|
d_cp += 1
|
||
|
if self.G.nodes[prov]['type'] == 'T':
|
||
|
t_cp += 1
|
||
|
else:
|
||
|
raise ValueError("Inconsistent data in the graph edge\
|
||
|
attributes")
|
||
|
elif e['type'] == 'peer':
|
||
|
if self.G.nodes[i]['type'] == 'M' and\
|
||
|
self.G.nodes[j]['type'] == 'M':
|
||
|
p_m_m += 1
|
||
|
if self.G.nodes[i]['type'] == 'CP' and\
|
||
|
self.G.nodes[j]['type'] == 'CP':
|
||
|
p_cp_cp += 1
|
||
|
if self.G.nodes[i]['type'] == 'M' and\
|
||
|
self.G.nodes[j]['type'] == 'CP' or\
|
||
|
self.G.nodes[i]['type'] == 'CP' and\
|
||
|
self.G.nodes[j]['type'] == 'M':
|
||
|
p_cp_m += 1
|
||
|
else:
|
||
|
raise ValueError("Unexpected data in the graph edge\
|
||
|
attributes")
|
||
|
|
||
|
assert almost_equal(d_m/len(self.M), 2 + (2.5*self.n)/10000, places=0)
|
||
|
assert almost_equal(d_cp/len(self.CP), 2 + (1.5*self.n)/10000, places=0)
|
||
|
assert almost_equal(d_c/len(self.C), 1 + (5*self.n)/100000, places=0)
|
||
|
|
||
|
assert almost_equal(p_m_m/len(self.M), 1 + (2*self.n)/10000, places=0)
|
||
|
assert almost_equal(p_cp_m/len(self.CP), 0.2 + (2*self.n)/10000, places=0)
|
||
|
assert almost_equal(p_cp_cp/len(self.CP), 0.05 + (2*self.n)/100000, places=0)
|
||
|
|
||
|
assert almost_equal(t_m/d_m, 0.375, places=1)
|
||
|
assert almost_equal(t_cp/d_cp, 0.375, places=1)
|
||
|
assert almost_equal(t_c/d_c, 0.125, places=1)
|