Completed
Pull Request — master (#58)
by
unknown
02:26
created

build.tests.unit.test_results_edges   B

Complexity

Total Complexity 50

Size/Duplication

Total Lines 505
Duplicated Lines 8.71 %

Importance

Changes 0
Metric Value
eloc 387
dl 44
loc 505
rs 8.4
c 0
b 0
f 0
wmc 50

13 Methods

Rating   Name   Duplication   Size   Complexity  
A TestResultsEdges.test_path10() 0 7 2
B TestResultsEdges.generate_topology() 0 56 1
A TestResultsEdges.test_path1() 0 6 2
C TestResultsEdges.test_path8() 22 69 11
A TestResultsEdges.test_path5() 0 13 4
B TestResultsEdges.test_path7() 0 63 4
A TestResultsEdges.test_path6() 0 29 4
B TestResultsEdges._fill_links() 0 65 1
A TestResultsEdges.test_path2() 0 7 2
A TestResultsEdges.test_path3() 0 21 4
A TestResultsEdges.test_path4() 0 13 4
C TestResultsEdges.test_path9() 22 70 10
B TestResultsEdges._add_metadata_to_links() 0 60 1

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like build.tests.unit.test_results_edges often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
"""Module to test the KytosGraph in graph.py."""
2
from itertools import combinations
3
4
# Core modules to import
5
from kytos.core.link import Link
6
7
# module under test
8
from tests.unit.test_results import TestResults
9
10
11
class TestResultsEdges(TestResults):
12
    """Tests for the graph class."""
13
14
    def test_path1(self):
15
        """Tests paths between all users using unconstrained path alogrithm."""
16
        combos = combinations(["User1", "User2", "User3", "User4"], 2)
17
        for point_a, point_b in combos:
18
            results = self.get_path(point_a, point_b)
19
            self.assertNotEqual(results, [])
20
21
    def test_path2(self):
22
        """Tests paths between all users using constrained path algorithm,
23
        with no constraints set."""
24
        combos = combinations(["User1", "User2", "User3", "User4"], 2)
25
        for point_a, point_b in combos:
26
            results = self.get_path_constrained(point_a, point_b)
27
            self.assertNotEqual(results, [])
28
29
    def test_path3(self):
30
        """Tests paths between all users using constrained path algorithm,
31
        with the ownership constraint set to B."""
32
        combos = combinations(["User1", "User2", "User3", "User4"], 2)
33
        for point_a, point_b in combos:
34
            results = self.get_path_constrained(
35
                point_a, point_b, base=dict(ownership="B"))
36
            for result in results:
37
                for path in result["paths"]:
38
                    self.assertNotIn("S4:1", path)
39
                    self.assertNotIn("S5:2", path)
40
                    self.assertNotIn("S4:2", path)
41
                    self.assertNotIn("User1:2", path)
42
                    self.assertNotIn("S5:4", path)
43
                    self.assertNotIn("S6:2", path)
44
                    self.assertNotIn("S6:5", path)
45
                    self.assertNotIn("S10:1", path)
46
                    self.assertNotIn("S8:6", path)
47
                    self.assertNotIn("S10:2", path)
48
                    self.assertNotIn("S10:3", path)
49
                    self.assertNotIn("User2:1", path)
50
51
    def test_path4(self):
52
        """Tests paths between all users using constrained path algorithm,
53
        with the reliability constraint set to 3."""
54
        combos = combinations(["User1", "User2", "User3", "User4"], 2)
55
        for point_a, point_b in combos:
56
            results = self.get_path_constrained(
57
                point_a, point_b, base=dict(reliability=3))
58
            for result in results:
59
                for path in result["paths"]:
60
                    self.assertNotIn("S4:1", path)
61
                    self.assertNotIn("S5:2", path)
62
                    self.assertNotIn("S5:3", path)
63
                    self.assertNotIn("S6:1", path)
64
65
    def test_path5(self):
66
        """Tests paths between all users using constrained path algorithm,
67
        with the bandwidth contraint set to 100."""
68
        combos = combinations(["User1", "User2", "User3", "User4"], 2)
69
        for point_a, point_b in combos:
70
            results = self.get_path_constrained(
71
                point_a, point_b, base=dict(bandwidth=100))
72
            for result in results:
73
                for path in result["paths"]:
74
                    self.assertNotIn("S3:1", path)
75
                    self.assertNotIn("S5:1", path)
76
                    self.assertNotIn("User1:4", path)
77
                    self.assertNotIn("User4:3", path)
78
79
    def test_path6(self):
80
        """Tests paths between all users using constrained path algorithm,
81
        with the delay constraint set to 50."""
82
        combos = combinations(["User1", "User2", "User3", "User4"], 2)
83
        for point_a, point_b in combos:
84
            results = self.get_path_constrained(
85
                point_a, point_b, base=dict(delay=50))
86
            for result in results:
87
                for path in result["paths"]:
88
                    self.assertNotIn("S1:1", path)
89
                    self.assertNotIn("S2:1", path)
90
                    self.assertNotIn("S3:1", path)
91
                    self.assertNotIn("S5:1", path)
92
                    self.assertNotIn("S4:2", path)
93
                    self.assertNotIn("User1:2", path)
94
                    self.assertNotIn("S5:5", path)
95
                    self.assertNotIn("S8:2", path)
96
                    self.assertNotIn("S5:6", path)
97
                    self.assertNotIn("User1:3", path)
98
                    self.assertNotIn("S6:3", path)
99
                    self.assertNotIn("S9:1", path)
100
                    self.assertNotIn("S6:4", path)
101
                    self.assertNotIn("S9:2", path)
102
                    self.assertNotIn("S6:5", path)
103
                    self.assertNotIn("S10:1", path)
104
                    self.assertNotIn("S8:5", path)
105
                    self.assertNotIn("S9:4", path)
106
                    self.assertNotIn("User1:4", path)
107
                    self.assertNotIn("User4:3", path)
108
109
    def test_path7(self):
110
        """Tests paths between all users using constrained path algorithm,
111
        with the delay constraint set to 50, the bandwidth constraint set
112
        to 100, the reliability contraint set to 3, and the ownership
113
        constraint set to 'B' """
114
        combos = combinations(["User1", "User2", "User3", "User4"], 2)
115
        for point_a, point_b in combos:
116
            results = self.get_path_constrained(
117
                point_a, point_b, base=dict(delay=50, bandwidth=100,
118
                                            reliability=3,
119
                                            ownership="B"))
120
            for result in results:
121
                for path in result["paths"]:
122
                    # delay = 50 checks
123
                    self.assertNotIn("S1:1", path)
124
                    self.assertNotIn("S2:1", path)
125
                    self.assertNotIn("S3:1", path)
126
                    self.assertNotIn("S5:1", path)
127
                    self.assertNotIn("S4:2", path)
128
                    self.assertNotIn("User1:2", path)
129
                    self.assertNotIn("S5:5", path)
130
                    self.assertNotIn("S8:2", path)
131
                    self.assertNotIn("S5:6", path)
132
                    self.assertNotIn("User1:3", path)
133
                    self.assertNotIn("S6:3", path)
134
                    self.assertNotIn("S9:1", path)
135
                    self.assertNotIn("S6:4", path)
136
                    self.assertNotIn("S9:2", path)
137
                    self.assertNotIn("S6:5", path)
138
                    self.assertNotIn("S10:1", path)
139
                    self.assertNotIn("S8:5", path)
140
                    self.assertNotIn("S9:4", path)
141
                    self.assertNotIn("User1:4", path)
142
                    self.assertNotIn("User4:3", path)
143
144
                    # bandwidth = 100 checks
145
146
                    self.assertNotIn("S3:1", path)
147
                    self.assertNotIn("S5:1", path)
148
                    self.assertNotIn("User1:4", path)
149
                    self.assertNotIn("User4:3", path)
150
151
                    # reliability = 3 checks
152
153
                    self.assertNotIn("S4:1", path)
154
                    self.assertNotIn("S5:2", path)
155
                    self.assertNotIn("S5:3", path)
156
                    self.assertNotIn("S6:1", path)
157
158
                    # ownership = "B" checks
159
160
                    self.assertNotIn("S4:1", path)
161
                    self.assertNotIn("S5:2", path)
162
                    self.assertNotIn("S4:2", path)
163
                    self.assertNotIn("User1:2", path)
164
                    self.assertNotIn("S5:4", path)
165
                    self.assertNotIn("S6:2", path)
166
                    self.assertNotIn("S6:5", path)
167
                    self.assertNotIn("S10:1", path)
168
                    self.assertNotIn("S8:6", path)
169
                    self.assertNotIn("S10:2", path)
170
                    self.assertNotIn("S10:3", path)
171
                    self.assertNotIn("User2:1", path)
172
173
    def test_path8(self):
174
        """Tests paths between all users using constrained path algorithm,
175
        with the delay constraint set to 50, the bandwidth constraint
176
        set to 100, the reliability contraint set to 3, and the ownership
177
        constraint set to 'B'
178
179
        Tests conducted with flexibility enabled"""
180
        combos = combinations(["User1", "User2", "User3", "User4"], 2)
181
        for point_a, point_b in combos:
182
            results = self.get_path_constrained(
183
                point_a, point_b, flexible=dict(delay=50, bandwidth=100,
184
                                                reliability=3,
185
                                                ownership="B"))
186
            for result in results:
187
                # delay = 50 checks
188 View Code Duplication
                if "delay" in result["metrics"]:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
189
                    for path in result["paths"]:
190
                        self.assertNotIn("S1:1", path)
191
                        self.assertNotIn("S2:1", path)
192
                        self.assertNotIn("S3:1", path)
193
                        self.assertNotIn("S5:1", path)
194
                        self.assertNotIn("S4:2", path)
195
                        self.assertNotIn("User1:2", path)
196
                        self.assertNotIn("S5:5", path)
197
                        self.assertNotIn("S8:2", path)
198
                        self.assertNotIn("S5:6", path)
199
                        self.assertNotIn("User1:3", path)
200
                        self.assertNotIn("S6:3", path)
201
                        self.assertNotIn("S9:1", path)
202
                        self.assertNotIn("S6:4", path)
203
                        self.assertNotIn("S9:2", path)
204
                        self.assertNotIn("S6:5", path)
205
                        self.assertNotIn("S10:1", path)
206
                        self.assertNotIn("S8:5", path)
207
                        self.assertNotIn("S9:4", path)
208
                        self.assertNotIn("User1:4", path)
209
                        self.assertNotIn("User4:3", path)
210
211
                # bandwidth = 100 checks
212
                if "bandwidth" in result["metrics"]:
213
                    for path in result["paths"]:
214
                        self.assertNotIn("S3:1", path)
215
                        self.assertNotIn("S5:1", path)
216
                        self.assertNotIn("User1:4", path)
217
                        self.assertNotIn("User4:3", path)
218
219
                # reliability = 3 checks
220
                if "reliability" in result["metrics"]:
221
                    for path in result["paths"]:
222
                        self.assertNotIn("S4:1", path)
223
                        self.assertNotIn("S5:2", path)
224
                        self.assertNotIn("S5:3", path)
225
                        self.assertNotIn("S6:1", path)
226
227
                # ownership = "B" checks
228
                if "ownership" in result["metrics"]:
229
                    for path in result["paths"]:
230
                        self.assertNotIn("S4:1", path)
231
                        self.assertNotIn("S5:2", path)
232
                        self.assertNotIn("S4:2", path)
233
                        self.assertNotIn("User1:2", path)
234
                        self.assertNotIn("S5:4", path)
235
                        self.assertNotIn("S6:2", path)
236
                        self.assertNotIn("S6:5", path)
237
                        self.assertNotIn("S10:1", path)
238
                        self.assertNotIn("S8:6", path)
239
                        self.assertNotIn("S10:2", path)
240
                        self.assertNotIn("S10:3", path)
241
                        self.assertNotIn("User2:1", path)
242
243
    def test_path9(self):
244
        """Tests paths between all users using constrained path algorithm,
245
        with the delay constraint set to 50, the bandwidth constraint
246
        set to 100, the reliability contraint set to 3, and the ownership
247
        constraint set to 'B'
248
249
        Tests conducted with all but ownership flexible"""
250
        combos = combinations(["User1", "User2", "User3", "User4"], 2)
251
        for point_a, point_b in combos:
252
            results = self.get_path_constrained(point_a, point_b,
253
                                                base={"ownership": "B"},
254
                                                flexible={"delay": 50,
255
                                                          "bandwidth": 100,
256
                                                          "reliability": 3})
257
            for result in results:
258
                # delay = 50 checks
259 View Code Duplication
                if "delay" in result["metrics"]:
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
260
                    for path in result["paths"]:
261
                        self.assertNotIn("S1:1", path)
262
                        self.assertNotIn("S2:1", path)
263
                        self.assertNotIn("S3:1", path)
264
                        self.assertNotIn("S5:1", path)
265
                        self.assertNotIn("S4:2", path)
266
                        self.assertNotIn("User1:2", path)
267
                        self.assertNotIn("S5:5", path)
268
                        self.assertNotIn("S8:2", path)
269
                        self.assertNotIn("S5:6", path)
270
                        self.assertNotIn("User1:3", path)
271
                        self.assertNotIn("S6:3", path)
272
                        self.assertNotIn("S9:1", path)
273
                        self.assertNotIn("S6:4", path)
274
                        self.assertNotIn("S9:2", path)
275
                        self.assertNotIn("S6:5", path)
276
                        self.assertNotIn("S10:1", path)
277
                        self.assertNotIn("S8:5", path)
278
                        self.assertNotIn("S9:4", path)
279
                        self.assertNotIn("User1:4", path)
280
                        self.assertNotIn("User4:3", path)
281
282
                # bandwidth = 100 checks
283
                if "bandwidth" in result["metrics"]:
284
                    for path in result["paths"]:
285
                        self.assertNotIn("S3:1", path)
286
                        self.assertNotIn("S5:1", path)
287
                        self.assertNotIn("User1:4", path)
288
                        self.assertNotIn("User4:3", path)
289
290
                # reliability = 3 checks
291
                if "reliability" in result["metrics"]:
292
                    for path in result["paths"]:
293
                        self.assertNotIn("S4:1", path)
294
                        self.assertNotIn("S5:2", path)
295
                        self.assertNotIn("S5:3", path)
296
                        self.assertNotIn("S6:1", path)
297
298
                # ownership = "B" checks
299
                self.assertIn("ownership", result["metrics"])
300
                for path in result["paths"]:
301
                    self.assertNotIn("S4:1", path)
302
                    self.assertNotIn("S5:2", path)
303
                    self.assertNotIn("S4:2", path)
304
                    self.assertNotIn("User1:2", path)
305
                    self.assertNotIn("S5:4", path)
306
                    self.assertNotIn("S6:2", path)
307
                    self.assertNotIn("S6:5", path)
308
                    self.assertNotIn("S10:1", path)
309
                    self.assertNotIn("S8:6", path)
310
                    self.assertNotIn("S10:2", path)
311
                    self.assertNotIn("S10:3", path)
312
                    self.assertNotIn("User2:1", path)
313
314
    def test_path10(self):
315
        """Tests that TypeError is generated by get_path_constrained
316
317
        Tests with ownership using an int type rather than string"""
318
        with self.assertRaises(TypeError):
319
            self.get_path_constrained(
320
                "User1", "User2", base={"ownership": 1})
321
322
    @ staticmethod
323
    def generate_topology():
324
        """Generates a predetermined topology"""
325
        switches = {}
326
        interfaces = {}
327
        links = {}
328
329
        TestResults.create_switch("S1", switches)
330
        TestResults.add_interfaces(2, switches["S1"], interfaces)
331
332
        TestResults.create_switch("S2", switches)
333
        TestResults.add_interfaces(2, switches["S2"], interfaces)
334
335
        TestResults.create_switch("S3", switches)
336
        TestResults.add_interfaces(6, switches["S3"], interfaces)
337
338
        TestResults.create_switch("S4", switches)
339
        TestResults.add_interfaces(2, switches["S4"], interfaces)
340
341
        TestResults.create_switch("S5", switches)
342
        TestResults.add_interfaces(6, switches["S5"], interfaces)
343
344
        TestResults.create_switch("S6", switches)
345
        TestResults.add_interfaces(5, switches["S6"], interfaces)
346
347
        TestResults.create_switch("S7", switches)
348
        TestResults.add_interfaces(2, switches["S7"], interfaces)
349
350
        TestResults.create_switch("S8", switches)
351
        TestResults.add_interfaces(8, switches["S8"], interfaces)
352
353
        TestResults.create_switch("S9", switches)
354
        TestResults.add_interfaces(4, switches["S9"], interfaces)
355
356
        TestResults.create_switch("S10", switches)
357
        TestResults.add_interfaces(3, switches["S10"], interfaces)
358
359
        TestResults.create_switch("S11", switches)
360
        TestResults.add_interfaces(3, switches["S11"], interfaces)
361
362
        TestResults.create_switch("User1", switches)
363
        TestResults.add_interfaces(4, switches["User1"], interfaces)
364
365
        TestResults.create_switch("User2", switches)
366
        TestResults.add_interfaces(2, switches["User2"], interfaces)
367
368
        TestResults.create_switch("User3", switches)
369
        TestResults.add_interfaces(2, switches["User3"], interfaces)
370
371
        TestResults.create_switch("User4", switches)
372
        TestResults.add_interfaces(3, switches["User4"], interfaces)
373
374
        TestResultsEdges._fill_links(links, interfaces)
375
        TestResultsEdges._add_metadata_to_links(links)
376
377
        return (switches, links)
378
379
    @ staticmethod
380
    def _add_metadata_to_links(links):
381
        links["S1:1<->S2:1"].extend_metadata(
382
            {"reliability": 5, "bandwidth": 100, "delay": 105})
383
        links["S1:2<->User1:1"].extend_metadata(
384
            {"reliability": 5, "bandwidth": 100, "delay": 1})
385
        links["S2:2<->User4:1"].extend_metadata(
386
            {"reliability": 5, "bandwidth": 100, "delay": 10})
387
        links["S3:1<->S5:1"].extend_metadata(
388
            {"reliability": 5, "bandwidth": 10, "delay": 112})
389
        links["S3:2<->S7:1"].extend_metadata(
390
            {"reliability": 5, "bandwidth": 100, "delay": 1})
391
        links["S3:3<->S8:1"].extend_metadata(
392
            {"reliability": 5, "bandwidth": 100, "delay": 1})
393
        links["S3:4<->S11:1"].extend_metadata(
394
            {"reliability": 3, "bandwidth": 100, "delay": 6})
395
        links["S3:5<->User3:1"].extend_metadata(
396
            {"reliability": 5, "bandwidth": 100, "delay": 1})
397
        links["S3:6<->User4:2"].extend_metadata(
398
            {"reliability": 5, "bandwidth": 100, "delay": 10})
399
        links["S4:1<->S5:2"].extend_metadata(
400
            {"reliability": 1, "bandwidth": 100, "delay": 30,
401
             "ownership": "A"})
402
        links["S4:2<->User1:2"].extend_metadata(
403
            {"reliability": 3, "bandwidth": 100, "delay": 110,
404
             "ownership": "A"})
405
        links["S5:3<->S6:1"].extend_metadata(
406
            {"reliability": 1, "bandwidth": 100, "delay": 40})
407
        links["S5:4<->S6:2"].extend_metadata(
408
            {"reliability": 3, "bandwidth": 100, "delay": 40,
409
             "ownership": "A"})
410
        links["S5:5<->S8:2"].extend_metadata(
411
            {"reliability": 5, "bandwidth": 100, "delay": 112})
412
        links["S5:6<->User1:3"].extend_metadata(
413
            {"reliability": 3, "bandwidth": 100, "delay": 60})
414
        links["S6:3<->S9:1"].extend_metadata(
415
            {"reliability": 3, "bandwidth": 100, "delay": 60})
416
        links["S6:4<->S9:2"].extend_metadata(
417
            {"reliability": 5, "bandwidth": 100, "delay": 62})
418
        links["S6:5<->S10:1"].extend_metadata(
419
            {"bandwidth": 100, "delay": 108, "ownership": "A"})
420
        links["S7:2<->S8:3"].extend_metadata(
421
            {"reliability": 5, "bandwidth": 100, "delay": 1})
422
        links["S8:4<->S9:3"].extend_metadata(
423
            {"reliability": 3, "bandwidth": 100, "delay": 32})
424
        links["S8:5<->S9:4"].extend_metadata(
425
            {"reliability": 3, "bandwidth": 100, "delay": 110})
426
        links["S8:6<->S10:2"].extend_metadata(
427
            {"reliability": 5, "bandwidth": 100, "ownership": "A"})
428
        links["S8:7<->S11:2"].extend_metadata(
429
            {"reliability": 3, "bandwidth": 100, "delay": 7})
430
        links["S8:8<->User3:2"].extend_metadata(
431
            {"reliability": 5, "bandwidth": 100, "delay": 1})
432
        links["S10:3<->User2:1"].extend_metadata(
433
            {"reliability": 3, "bandwidth": 100, "delay": 10,
434
             "ownership": "A"})
435
        links["S11:3<->User2:2"].extend_metadata(
436
            {"reliability": 3, "bandwidth": 100, "delay": 6})
437
        links["User1:4<->User4:3"].extend_metadata(
438
            {"reliability": 5, "bandwidth": 10, "delay": 105})
439
440
    @ staticmethod
441
    def _fill_links(links, interfaces):
442
        links["S1:1<->S2:1"] = Link(interfaces["S1:1"], interfaces["S2:1"])
443
444
        links["S1:2<->User1:1"] = Link(interfaces["S1:2"],
445
                                       interfaces["User1:1"])
446
447
        links["S2:2<->User4:1"] = Link(interfaces["S2:2"],
448
                                       interfaces["User4:1"])
449
450
        links["S3:1<->S5:1"] = Link(interfaces["S3:1"], interfaces["S5:1"])
451
452
        links["S3:2<->S7:1"] = Link(interfaces["S3:2"], interfaces["S7:1"])
453
454
        links["S3:3<->S8:1"] = Link(interfaces["S3:3"], interfaces["S8:1"])
455
456
        links["S3:4<->S11:1"] = Link(interfaces["S3:4"], interfaces["S11:1"])
457
458
        links["S3:5<->User3:1"] = Link(interfaces["S3:5"],
459
                                       interfaces["User3:1"])
460
461
        links["S3:6<->User4:2"] = Link(interfaces["S3:6"],
462
                                       interfaces["User4:2"])
463
464
        links["S4:1<->S5:2"] = Link(interfaces["S4:1"], interfaces["S5:2"])
465
466
        links["S4:2<->User1:2"] = Link(interfaces["S4:2"],
467
                                       interfaces["User1:2"])
468
469
        links["S5:3<->S6:1"] = Link(interfaces["S5:3"], interfaces["S6:1"])
470
471
        links["S5:4<->S6:2"] = Link(interfaces["S5:4"], interfaces["S6:2"])
472
473
        links["S5:5<->S8:2"] = Link(interfaces["S5:5"], interfaces["S8:2"])
474
475
        links["S5:6<->User1:3"] = Link(interfaces["S5:6"],
476
                                       interfaces["User1:3"])
477
478
        links["S6:3<->S9:1"] = Link(interfaces["S6:3"], interfaces["S9:1"])
479
480
        links["S6:4<->S9:2"] = Link(interfaces["S6:4"], interfaces["S9:2"])
481
482
        links["S6:5<->S10:1"] = Link(interfaces["S6:5"], interfaces["S10:1"])
483
484
        links["S7:2<->S8:3"] = Link(interfaces["S7:2"], interfaces["S8:3"])
485
486
        links["S8:4<->S9:3"] = Link(interfaces["S8:4"], interfaces["S9:3"])
487
488
        links["S8:5<->S9:4"] = Link(interfaces["S8:5"], interfaces["S9:4"])
489
490
        links["S8:6<->S10:2"] = Link(interfaces["S8:6"], interfaces["S10:2"])
491
492
        links["S8:7<->S11:2"] = Link(interfaces["S8:7"], interfaces["S11:2"])
493
494
        links["S8:8<->User3:2"] = Link(interfaces["S8:8"],
495
                                       interfaces["User3:2"])
496
497
        links["S10:3<->User2:1"] = Link(interfaces["S10:3"],
498
                                        interfaces["User2:1"])
499
500
        links["S11:3<->User2:2"] = Link(interfaces["S11:3"],
501
                                        interfaces["User2:2"])
502
503
        links["User1:4<->User4:3"] = Link(interfaces["User1:4"],
504
                                          interfaces["User4:3"])
505