mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-22 01:13:00 +02:00
doc/testing: Add an overview of the test system
This commit is contained in:
committed by
Joachim Wiberg
parent
4e69f800de
commit
77f9ca8e2a
@@ -0,0 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: dhcp-client-server Pages: 1 -->
|
||||
<svg width="309pt" height="252pt"
|
||||
viewBox="0.00 0.00 308.52 252.02" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 248.02)">
|
||||
<title>dhcp-client-server</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-248.02 304.52,-248.02 304.52,4 -4,4"/>
|
||||
<!-- host -->
|
||||
<g id="node1" class="node">
|
||||
<title>host</title>
|
||||
<polygon fill="none" stroke="grey" points="0,-87.51 0,-156.51 91,-156.51 91,-87.51 0,-87.51"/>
|
||||
<text text-anchor="middle" x="25" y="-118.31" font-family="monospace" font-size="14.00" fill="grey">host</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-87.51 50,-156.51 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-141.31" font-family="monospace" font-size="14.00" fill="grey">c1</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-133.51 91,-133.51 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-118.31" font-family="monospace" font-size="14.00" fill="grey">srv</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-110.51 91,-110.51 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-95.31" font-family="monospace" font-size="14.00" fill="grey">c2</text>
|
||||
</g>
|
||||
<!-- server -->
|
||||
<g id="node2" class="node">
|
||||
<title>server</title>
|
||||
<polygon fill="none" stroke="black" points="143.52,-99.01 143.52,-145.01 292.52,-145.01 292.52,-99.01 143.52,-99.01"/>
|
||||
<text text-anchor="middle" x="168.52" y="-118.31" font-family="monospace" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="193.52,-99.01 193.52,-145.01 "/>
|
||||
<text text-anchor="middle" x="226.52" y="-118.31" font-family="monospace" font-size="14.00">server</text>
|
||||
<polyline fill="none" stroke="black" points="259.52,-99.01 259.52,-145.01 "/>
|
||||
<text text-anchor="middle" x="276.02" y="-129.81" font-family="monospace" font-size="14.00">c1</text>
|
||||
<polyline fill="none" stroke="black" points="259.52,-122.01 292.52,-122.01 "/>
|
||||
<text text-anchor="middle" x="276.02" y="-106.81" font-family="monospace" font-size="14.00">c2</text>
|
||||
</g>
|
||||
<!-- host--server -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>host:srv--server:mgmt</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-122.01C91.5,-122.01 143.02,-122.01 143.02,-122.01"/>
|
||||
</g>
|
||||
<!-- client1 -->
|
||||
<g id="node3" class="node">
|
||||
<title>client1</title>
|
||||
<polygon fill="none" stroke="black" points="135.52,-207.52 135.52,-243.52 300.52,-243.52 300.52,-207.52 135.52,-207.52"/>
|
||||
<text text-anchor="middle" x="160.52" y="-221.82" font-family="monospace" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="185.52,-207.52 185.52,-243.52 "/>
|
||||
<text text-anchor="middle" x="222.52" y="-221.82" font-family="monospace" font-size="14.00">client1</text>
|
||||
<polyline fill="none" stroke="black" points="259.52,-207.52 259.52,-243.52 "/>
|
||||
<text text-anchor="middle" x="280.02" y="-221.82" font-family="monospace" font-size="14.00">srv</text>
|
||||
</g>
|
||||
<!-- host--client1 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>host:c1--client1:mgmt</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-145.01C91.5,-145.01 135.02,-225.52 135.02,-225.52"/>
|
||||
</g>
|
||||
<!-- client2 -->
|
||||
<g id="node4" class="node">
|
||||
<title>client2</title>
|
||||
<polygon fill="none" stroke="black" points="135.52,-0.5 135.52,-36.5 300.52,-36.5 300.52,-0.5 135.52,-0.5"/>
|
||||
<text text-anchor="middle" x="160.52" y="-14.8" font-family="monospace" font-size="14.00">mgmt</text>
|
||||
<polyline fill="none" stroke="black" points="185.52,-0.5 185.52,-36.5 "/>
|
||||
<text text-anchor="middle" x="222.52" y="-14.8" font-family="monospace" font-size="14.00">client2</text>
|
||||
<polyline fill="none" stroke="black" points="259.52,-0.5 259.52,-36.5 "/>
|
||||
<text text-anchor="middle" x="280.02" y="-14.8" font-family="monospace" font-size="14.00">srv</text>
|
||||
</g>
|
||||
<!-- host--client2 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>host:c2--client2:mgmt</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-99.01C91.5,-99.01 135.02,-18.5 135.02,-18.5"/>
|
||||
</g>
|
||||
<!-- server--client1 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>server:c1--client1:srv</title>
|
||||
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M276.02,-145.01C276.02,-145.01 280.02,-207.52 280.02,-207.52"/>
|
||||
</g>
|
||||
<!-- server--client2 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>server:c2--client2:srv</title>
|
||||
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M276.02,-99.01C276.02,-99.01 280.02,-36.5 280.02,-36.5"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.6 KiB |
File diff suppressed because one or more lines are too long
|
After Width: | Height: | Size: 416 KiB |
@@ -0,0 +1,187 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
|
||||
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<!-- Generated by graphviz version 2.43.0 (0)
|
||||
-->
|
||||
<!-- Title: quad-ring Pages: 1 -->
|
||||
<svg width="347pt" height="438pt"
|
||||
viewBox="0.00 0.00 346.65 438.04" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
||||
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 434.04)">
|
||||
<title>quad-ring</title>
|
||||
<polygon fill="white" stroke="transparent" points="-4,4 -4,-434.04 342.65,-434.04 342.65,4 -4,4"/>
|
||||
<!-- host -->
|
||||
<g id="node1" class="node">
|
||||
<title>host</title>
|
||||
<polygon fill="none" stroke="grey" points="0,-77.02 0,-353.02 91,-353.02 91,-77.02 0,-77.02"/>
|
||||
<text text-anchor="middle" x="25" y="-211.32" font-family="monospace" font-size="14.00" fill="grey">host</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-77.02 50,-353.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-337.82" font-family="monospace" font-size="14.00" fill="grey">d1a</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-330.02 91,-330.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-314.82" font-family="monospace" font-size="14.00" fill="grey">d1b</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-307.02 91,-307.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-291.82" font-family="monospace" font-size="14.00" fill="grey">d1c</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-284.02 91,-284.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-268.82" font-family="monospace" font-size="14.00" fill="grey">d2a</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-261.02 91,-261.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-245.82" font-family="monospace" font-size="14.00" fill="grey">d2b</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-238.02 91,-238.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-222.82" font-family="monospace" font-size="14.00" fill="grey">d2c</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-215.02 91,-215.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-199.82" font-family="monospace" font-size="14.00" fill="grey">d3a</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-192.02 91,-192.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-176.82" font-family="monospace" font-size="14.00" fill="grey">d3b</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-169.02 91,-169.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-153.82" font-family="monospace" font-size="14.00" fill="grey">d3c</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-146.02 91,-146.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-130.82" font-family="monospace" font-size="14.00" fill="grey">d4a</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-123.02 91,-123.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-107.82" font-family="monospace" font-size="14.00" fill="grey">d4b</text>
|
||||
<polyline fill="none" stroke="grey" points="50,-100.02 91,-100.02 "/>
|
||||
<text text-anchor="middle" x="70.5" y="-84.82" font-family="monospace" font-size="14.00" fill="grey">d4c</text>
|
||||
</g>
|
||||
<!-- dut1 -->
|
||||
<g id="node2" class="node">
|
||||
<title>dut1</title>
|
||||
<polygon fill="none" stroke="black" points="187.52,-360.54 187.52,-429.54 303.52,-429.54 303.52,-360.54 187.52,-360.54"/>
|
||||
<text text-anchor="middle" x="204.02" y="-414.34" font-family="monospace" font-size="14.00">e1</text>
|
||||
<polyline fill="none" stroke="black" points="187.52,-406.54 220.52,-406.54 "/>
|
||||
<text text-anchor="middle" x="204.02" y="-391.34" font-family="monospace" font-size="14.00">e2</text>
|
||||
<polyline fill="none" stroke="black" points="187.52,-383.54 220.52,-383.54 "/>
|
||||
<text text-anchor="middle" x="204.02" y="-368.34" font-family="monospace" font-size="14.00">e3</text>
|
||||
<polyline fill="none" stroke="black" points="220.52,-360.54 220.52,-429.54 "/>
|
||||
<text text-anchor="middle" x="245.52" y="-391.34" font-family="monospace" font-size="14.00">dut1</text>
|
||||
<polyline fill="none" stroke="black" points="270.52,-360.54 270.52,-429.54 "/>
|
||||
<text text-anchor="middle" x="287.02" y="-408.84" font-family="monospace" font-size="14.00">e4</text>
|
||||
<polyline fill="none" stroke="black" points="270.52,-395.54 303.52,-395.54 "/>
|
||||
<text text-anchor="middle" x="287.02" y="-374.34" font-family="monospace" font-size="14.00">e5</text>
|
||||
</g>
|
||||
<!-- host--dut1 -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>host:d1a--dut1:e1</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-342.02C91.5,-342.02 187.52,-418.04 187.52,-418.04"/>
|
||||
</g>
|
||||
<!-- host--dut1 -->
|
||||
<g id="edge5" class="edge">
|
||||
<title>host:d1b--dut1:e2</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-319.02C91.5,-319.02 187.52,-395.04 187.52,-395.04"/>
|
||||
</g>
|
||||
<!-- host--dut1 -->
|
||||
<g id="edge9" class="edge">
|
||||
<title>host:d1c--dut1:e3</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-296.02C91.5,-296.02 187.52,-372.04 187.52,-372.04"/>
|
||||
</g>
|
||||
<!-- dut2 -->
|
||||
<g id="node3" class="node">
|
||||
<title>dut2</title>
|
||||
<polygon fill="none" stroke="black" points="187.52,-240.52 187.52,-309.52 303.52,-309.52 303.52,-240.52 187.52,-240.52"/>
|
||||
<text text-anchor="middle" x="204.02" y="-294.32" font-family="monospace" font-size="14.00">e1</text>
|
||||
<polyline fill="none" stroke="black" points="187.52,-286.52 220.52,-286.52 "/>
|
||||
<text text-anchor="middle" x="204.02" y="-271.32" font-family="monospace" font-size="14.00">e2</text>
|
||||
<polyline fill="none" stroke="black" points="187.52,-263.52 220.52,-263.52 "/>
|
||||
<text text-anchor="middle" x="204.02" y="-248.32" font-family="monospace" font-size="14.00">e3</text>
|
||||
<polyline fill="none" stroke="black" points="220.52,-240.52 220.52,-309.52 "/>
|
||||
<text text-anchor="middle" x="245.52" y="-271.32" font-family="monospace" font-size="14.00">dut2</text>
|
||||
<polyline fill="none" stroke="black" points="270.52,-240.52 270.52,-309.52 "/>
|
||||
<text text-anchor="middle" x="287.02" y="-288.82" font-family="monospace" font-size="14.00">e4</text>
|
||||
<polyline fill="none" stroke="black" points="270.52,-275.52 303.52,-275.52 "/>
|
||||
<text text-anchor="middle" x="287.02" y="-254.32" font-family="monospace" font-size="14.00">e5</text>
|
||||
</g>
|
||||
<!-- host--dut2 -->
|
||||
<g id="edge2" class="edge">
|
||||
<title>host:d2a--dut2:e1</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-273.02C91.5,-273.02 187.52,-298.02 187.52,-298.02"/>
|
||||
</g>
|
||||
<!-- host--dut2 -->
|
||||
<g id="edge6" class="edge">
|
||||
<title>host:d2b--dut2:e2</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-250.02C91.5,-250.02 187.52,-275.02 187.52,-275.02"/>
|
||||
</g>
|
||||
<!-- host--dut2 -->
|
||||
<g id="edge10" class="edge">
|
||||
<title>host:d2c--dut2:e3</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-227.02C91.5,-227.02 187.52,-252.02 187.52,-252.02"/>
|
||||
</g>
|
||||
<!-- dut3 -->
|
||||
<g id="node4" class="node">
|
||||
<title>dut3</title>
|
||||
<polygon fill="none" stroke="black" points="187.52,-120.51 187.52,-189.51 303.52,-189.51 303.52,-120.51 187.52,-120.51"/>
|
||||
<text text-anchor="middle" x="204.02" y="-174.31" font-family="monospace" font-size="14.00">e1</text>
|
||||
<polyline fill="none" stroke="black" points="187.52,-166.51 220.52,-166.51 "/>
|
||||
<text text-anchor="middle" x="204.02" y="-151.31" font-family="monospace" font-size="14.00">e2</text>
|
||||
<polyline fill="none" stroke="black" points="187.52,-143.51 220.52,-143.51 "/>
|
||||
<text text-anchor="middle" x="204.02" y="-128.31" font-family="monospace" font-size="14.00">e3</text>
|
||||
<polyline fill="none" stroke="black" points="220.52,-120.51 220.52,-189.51 "/>
|
||||
<text text-anchor="middle" x="245.52" y="-151.31" font-family="monospace" font-size="14.00">dut3</text>
|
||||
<polyline fill="none" stroke="black" points="270.52,-120.51 270.52,-189.51 "/>
|
||||
<text text-anchor="middle" x="287.02" y="-168.81" font-family="monospace" font-size="14.00">e4</text>
|
||||
<polyline fill="none" stroke="black" points="270.52,-155.51 303.52,-155.51 "/>
|
||||
<text text-anchor="middle" x="287.02" y="-134.31" font-family="monospace" font-size="14.00">e5</text>
|
||||
</g>
|
||||
<!-- host--dut3 -->
|
||||
<g id="edge3" class="edge">
|
||||
<title>host:d3a--dut3:e1</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-203.02C91.5,-203.02 187.52,-178.01 187.52,-178.01"/>
|
||||
</g>
|
||||
<!-- host--dut3 -->
|
||||
<g id="edge7" class="edge">
|
||||
<title>host:d3b--dut3:e2</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-180.02C91.5,-180.02 187.52,-155.01 187.52,-155.01"/>
|
||||
</g>
|
||||
<!-- host--dut3 -->
|
||||
<g id="edge11" class="edge">
|
||||
<title>host:d3c--dut3:e3</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-157.02C91.5,-157.02 187.52,-132.01 187.52,-132.01"/>
|
||||
</g>
|
||||
<!-- dut4 -->
|
||||
<g id="node5" class="node">
|
||||
<title>dut4</title>
|
||||
<polygon fill="none" stroke="black" points="187.52,-0.5 187.52,-69.5 303.52,-69.5 303.52,-0.5 187.52,-0.5"/>
|
||||
<text text-anchor="middle" x="204.02" y="-54.3" font-family="monospace" font-size="14.00">e1</text>
|
||||
<polyline fill="none" stroke="black" points="187.52,-46.5 220.52,-46.5 "/>
|
||||
<text text-anchor="middle" x="204.02" y="-31.3" font-family="monospace" font-size="14.00">e2</text>
|
||||
<polyline fill="none" stroke="black" points="187.52,-23.5 220.52,-23.5 "/>
|
||||
<text text-anchor="middle" x="204.02" y="-8.3" font-family="monospace" font-size="14.00">e3</text>
|
||||
<polyline fill="none" stroke="black" points="220.52,-0.5 220.52,-69.5 "/>
|
||||
<text text-anchor="middle" x="245.52" y="-31.3" font-family="monospace" font-size="14.00">dut4</text>
|
||||
<polyline fill="none" stroke="black" points="270.52,-0.5 270.52,-69.5 "/>
|
||||
<text text-anchor="middle" x="287.02" y="-48.8" font-family="monospace" font-size="14.00">e4</text>
|
||||
<polyline fill="none" stroke="black" points="270.52,-35.5 303.52,-35.5 "/>
|
||||
<text text-anchor="middle" x="287.02" y="-14.3" font-family="monospace" font-size="14.00">e5</text>
|
||||
</g>
|
||||
<!-- host--dut4 -->
|
||||
<g id="edge4" class="edge">
|
||||
<title>host:d4a--dut4:e1</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-134.02C91.5,-134.02 187.52,-58 187.52,-58"/>
|
||||
</g>
|
||||
<!-- host--dut4 -->
|
||||
<g id="edge8" class="edge">
|
||||
<title>host:d4b--dut4:e2</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-111.02C91.5,-111.02 187.52,-35 187.52,-35"/>
|
||||
</g>
|
||||
<!-- host--dut4 -->
|
||||
<g id="edge12" class="edge">
|
||||
<title>host:d4c--dut4:e3</title>
|
||||
<path fill="none" stroke="grey" stroke-width="2" d="M91.5,-88.02C91.5,-88.02 187.52,-12 187.52,-12"/>
|
||||
</g>
|
||||
<!-- dut1--dut2 -->
|
||||
<g id="edge13" class="edge">
|
||||
<title>dut1:e5--dut2:e4</title>
|
||||
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M287.52,-360.04C287.52,-360.04 287.52,-310.02 287.52,-310.02"/>
|
||||
</g>
|
||||
<!-- dut2--dut3 -->
|
||||
<g id="edge14" class="edge">
|
||||
<title>dut2:e5--dut3:e4</title>
|
||||
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M287.52,-240.02C287.52,-240.02 287.52,-190.01 287.52,-190.01"/>
|
||||
</g>
|
||||
<!-- dut3--dut4 -->
|
||||
<g id="edge15" class="edge">
|
||||
<title>dut3:e5--dut4:e4</title>
|
||||
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M287.52,-120.01C287.52,-120.01 287.52,-70 287.52,-70"/>
|
||||
</g>
|
||||
<!-- dut4--dut1 -->
|
||||
<g id="edge16" class="edge">
|
||||
<title>dut4:e5--dut1:e4</title>
|
||||
<path fill="none" stroke="cornflowerblue" stroke-width="2" d="M303.6,-18.06C303.6,-18.06 319.05,-56.84 323.52,-89.5 338.65,-200.04 338.45,-229.97 323.52,-340.54 319.05,-373.62 303.59,-412.97 303.59,-412.97"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
+273
@@ -0,0 +1,273 @@
|
||||
Testing
|
||||
=======
|
||||
|
||||
Infix comes with a test suite that is intended to provide end-to-end
|
||||
verification of supported features. Generally speaking, this means
|
||||
that one or more DUTs are configured over NETCONF; the resulting
|
||||
network is then black-box tested by injecting and inspecting network
|
||||
traffic at various points.
|
||||
|
||||
|
||||
TL;DR
|
||||
-----
|
||||
|
||||
make x86_64_defconfig
|
||||
make
|
||||
make test-qeneth
|
||||
|
||||
Runs the test suite on a set of virtual Infix nodes.
|
||||
|
||||
|
||||
Tenets
|
||||
------
|
||||
|
||||
- **Keep overhead to a minimum**. Tests should be fast to both write
|
||||
and run. Ideally, the developer should _want_ to add tests early in
|
||||
the development cycle because they instinctively feel that that is
|
||||
the quickest route to arrive at a correct and robust implementation.
|
||||
|
||||
- **Both physical and virtual hardware matters**. Infix is primarily
|
||||
deployed on physical hardware, so being able to run the test suite
|
||||
on real devices is crucial to guarantee a high quality product. At
|
||||
the same time, there is much value in running the same suite on
|
||||
virtual hardware, as it makes it easy to catch regressions early.
|
||||
It is also much more practical and economical to build large virtual
|
||||
networks than physical ones.
|
||||
|
||||
- **Avoid CLI scipting & scraping**. Reliably interacting with a DUT
|
||||
over a serial line in a robust way is _very_ hard to get right.
|
||||
Given that we have a proper API (RESTCONF), we should leverage that
|
||||
when testing. Front-ends can be tested by other means.
|
||||
|
||||
|
||||
Architectural Overview
|
||||
----------------------
|
||||
|
||||

|
||||
|
||||
The test system is made up of several independent components, which
|
||||
are typically used in concert to run a full test suite.
|
||||
|
||||
### Test Cases
|
||||
|
||||
A test case is an executable, receiving the physical topology as a
|
||||
positional argument, which produces [TAP][] compliant output on its
|
||||
`stdout`. I.e., it is executed in the following manner:
|
||||
|
||||
test-case [OPTS] <physical-topology>
|
||||
|
||||
Test cases are typically written in Python, using the
|
||||
[Infamy](#infamy) library. Ultimately though, it can be implemented
|
||||
in any language, as long as it matches the calling convention above.
|
||||
|
||||
### Infamy
|
||||
|
||||
Rather than having each test case come up with its own implementation
|
||||
of how to map topologies, how to push NETCONF data to a device, etc.,
|
||||
we provide a library of functions to take care of all that, dubbed
|
||||
"Infamy". When adding a new test case, ask yourself if any parts of
|
||||
it might belong in Infamy as a generalized component that can be
|
||||
reused by other tests.
|
||||
|
||||
Some of the core functions provided by Infamy are:
|
||||
|
||||
- Mapping a logical topology to a physical one
|
||||
- Finding and attaching to a device over an Ethernet interface, using
|
||||
NETCONF
|
||||
- Pushing/pulling NETCONF data to/from a device
|
||||
- Generating TAP compliant output
|
||||
|
||||
### 9PM
|
||||
|
||||
To run multiple tests, we employ [9PM][]. It let's us define test
|
||||
suites as simple YAML files. Suites can also be hierarchically
|
||||
structured, with a suite being made up of other suites, etc.
|
||||
|
||||
It also validates the TAP output, making sure to catch early exits
|
||||
from a case, and produces a nice summary report.
|
||||
|
||||
### `/test/env`
|
||||
|
||||
A good way to ensure that nobody ever runs the test suite is to make
|
||||
it _really_ hard to do so. `/test/env`'s job is instead to make it
|
||||
very _easy_ to create a reproducible environment in which tests can be
|
||||
executed.
|
||||
|
||||
Several technologies are leveraged to accomplish this:
|
||||
|
||||
- **Containers**: The entire execution is optionally done inside a
|
||||
standardized container environment, using either `podman` or
|
||||
`docker`. This ensures that the software needed to run the test
|
||||
suite is always available, no matter which distribution the user is
|
||||
running on their machine.
|
||||
|
||||
- **Python Virtual Environments**: To make sure that the expected
|
||||
versions of all Python packages are available, the execution is
|
||||
wrapped inside a `venv`. This is true for containerized executions,
|
||||
where the container comes with a pre-installed environment, but it
|
||||
can also be sourced from the host system when running outside of the
|
||||
container.
|
||||
|
||||
- **Virtual Test Topology**: Using [Qeneth][], the environment can
|
||||
optionally be started with a virtual topology of DUTs to run the
|
||||
tests on.
|
||||
|
||||
|
||||
Interactive Usage
|
||||
-----------------
|
||||
|
||||
Some tests only require a single DUT. These can therefore be run
|
||||
against an Infix image started from `make run`. When the instance is
|
||||
running, you can open a separate terminal and run `make test-run`, to
|
||||
run the subset of the test suite that can be mapped to it.
|
||||
|
||||
Both `test-qeneth` and `test-run` targets have a respective target
|
||||
with a `-sh` suffix. These can be used to start an interactive
|
||||
session in the reproducible environment, which is usually much easier
|
||||
to work with during a debugging session.
|
||||
|
||||
Inside of the reproducible environment, a wrapper for Qeneth is
|
||||
automatically created that will run it from the running network's
|
||||
directory. E.g., running a plain `qeneth status` inside a `make
|
||||
test-qeneth-sh` environment will show the expected status information.
|
||||
|
||||
|
||||
Physical and Logical Topologies
|
||||
-------------------------------
|
||||
|
||||
Imagine that we want to create a test with three DUTs; one acting as a
|
||||
DHCP server, and the other two as DHCP clients - with all three having
|
||||
a management connection to the host PC running the test. In other
|
||||
words, the test requires a _logical_ topology like the one below.
|
||||
|
||||
<img align="right" src="testing-log.dot.svg" alt="Example Logical Topology">
|
||||
|
||||
graph "dhcp-client-server" {
|
||||
host [
|
||||
label="host | { <c1> c1 | <srv> srv | <c2> c2 }",
|
||||
kind="controller",
|
||||
];
|
||||
|
||||
server [
|
||||
label="{ <mgmt> mgmt } | server | { <c1> c1 | <c2> c2 }",
|
||||
kind="infix",
|
||||
];
|
||||
client1 [
|
||||
label="{ <mgmt> mgmt } | client1 | { <srv> srv }",
|
||||
kind="infix",
|
||||
];
|
||||
client2 [
|
||||
label="{ <mgmt> mgmt } | client2 | { <srv> srv }",
|
||||
kind="infix",
|
||||
];
|
||||
|
||||
host:srv -- server:mgmt
|
||||
host:c1 -- client1:mgmt
|
||||
host:c2 -- client2:mgmt
|
||||
|
||||
server:c1 -- client1:srv;
|
||||
server:c2 -- client2:srv;
|
||||
}
|
||||
|
||||
When running in a virtualized environment, one could simply create a
|
||||
setup that matches the test's logical topology. But in scenarios when
|
||||
devices are physical systems, connected by real copper cables, this is
|
||||
not possible (unless you have some wicked L1 relay matrix thingy).
|
||||
|
||||
Instead, the test implementation does not concern itself with the
|
||||
exact nodes used to run the test, only that the _logical_ topology can
|
||||
be _mapped_ to some subset of the _physical_ topology. In
|
||||
mathematical terms, the physical topology must contain a subgraph that
|
||||
is _isomorphic_ to the logical topology.
|
||||
|
||||
Standing on the shoulders of giants (i.e. people with mathematics
|
||||
degrees), we can deploy well-known algorithms to find such subgraphs.
|
||||
Continuing our example, let's say we want to run our DHCP test on the
|
||||
_physical_ topology below.
|
||||
|
||||
<img align="right" src="testing-phy.dot.svg" alt="Example Physical Topology">
|
||||
|
||||
graph "quad-ring" {
|
||||
host [
|
||||
label="host | { <d1a> d1a | <d1b> d1b | <d1c> d1c | <d2a> d2a | <d2b> d2b | <d2c> d2c | <d3a> d3a | <d3b> d3b | <d3c> d3c | <d4a> d4a | <d4b> d4b | <d4c> d4c }",
|
||||
kind="controller",
|
||||
];
|
||||
|
||||
dut1 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut1 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
dut2 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut2 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
dut3 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut3 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
dut4 [
|
||||
label="{ <e1> e1 | <e2> e2 | <e3> e3 } | dut4 | { <e4> e4 | <e5> e5 }",
|
||||
kind="infix",
|
||||
];
|
||||
|
||||
host:d1a -- dut1:e1
|
||||
host:d1b -- dut1:e2
|
||||
host:d1c -- dut1:e3
|
||||
|
||||
host:d2a -- dut2:e1
|
||||
host:d2b -- dut2:e2
|
||||
host:d2c -- dut2:e3
|
||||
|
||||
host:d3a -- dut3:e1
|
||||
host:d3b -- dut3:e2
|
||||
host:d3c -- dut3:e3
|
||||
|
||||
host:d4a -- dut4:e1
|
||||
host:d4b -- dut4:e2
|
||||
host:d4c -- dut4:e3
|
||||
|
||||
dut1:e5 -- dut2:e4
|
||||
dut2:e5 -- dut3:e4
|
||||
dut3:e5 -- dut4:e4
|
||||
dut4:e5 -- dut1:e4
|
||||
}
|
||||
|
||||
Our test (in fact, all tests) receives the physical topology as an
|
||||
input parameter, and then maps the desired logical topology onto it,
|
||||
producing a mapping from logical nodes and ports to their physical
|
||||
counterparts.
|
||||
|
||||
{
|
||||
"client1": "dut1",
|
||||
"client1:mgmt": "dut1:e1",
|
||||
"client1:srv": "dut1:e4",
|
||||
"client2": "dut3",
|
||||
"client2:mgmt": "dut3:e2",
|
||||
"client2:srv": "dut3:e5",
|
||||
"host": "host",
|
||||
"host:c1": "host:d1a",
|
||||
"host:c2": "host:d3b",
|
||||
"host:srv": "host:d4c",
|
||||
"server": "dut4",
|
||||
"server:c1": "dut4:e5",
|
||||
"server:c2": "dut4:e4",
|
||||
"server:mgmt": "dut4:e3"
|
||||
}
|
||||
|
||||
With this information, the test knows that, in this particular
|
||||
environment, the server should be managed via the port called `d4c` on
|
||||
the node called `host`; that the port connected to the server on
|
||||
`client1` is `e4` on `dut1`, etc. Thereby separating the
|
||||
implementation of the test from any specific physical setup.
|
||||
|
||||
Testcases are not required to use a logical topology; they may choose
|
||||
to accept whatever physical topology its given, and dynamically
|
||||
determine the DUTs to use for testing. As an example, an STP test
|
||||
could accept an arbitrary physical topology, run the STP algorithm on
|
||||
it offline, enable STP on all DUTs, and then verify that the resulting
|
||||
spanning tree matches the expected one.
|
||||
|
||||
|
||||
[9PM]: https://github.com/rical/9pm
|
||||
[Qeneth]: https://github.com/wkz/qeneth
|
||||
[TAP]: https://testanything.org/
|
||||
Reference in New Issue
Block a user