Skip to content

Commit bc39ca7

Browse files
committed
CI: Run tests on PRs
1 parent 00d46a8 commit bc39ca7

File tree

13 files changed

+363
-70
lines changed

13 files changed

+363
-70
lines changed

.flake8

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@ ignore =
88
# disable warnings that conflict with Black
99
E203
1010
E701
11+
W503
12+
# at least two space before in-line comment
13+
E261
1114

1215
exclude =
1316
.git
Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
name: Check Pull Request
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- master
7+
- development
8+
- feature/ci
9+
10+
jobs:
11+
compile-examples:
12+
name: Compile Examples
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
16+
steps:
17+
- name: Check out the source repository
18+
uses: actions/checkout@v4
19+
- name: Set up Python
20+
uses: actions/setup-python@v5
21+
with:
22+
python-version: "3.10"
23+
cache: 'pip'
24+
cache-dependency-path: "**/*requirements.txt"
25+
- run: pip install -r requirements.txt -r dev-requirements.txt -r tests/requirements.txt
26+
- name: Get scion-pki
27+
run: |
28+
curl -fsSL -O https://github.com/scionproto/scion/releases/download/v0.12.0/scion_0.12.0_amd64_linux.tar.gz
29+
mkdir bin
30+
tar -C bin -xzf scion_0.12.0_amd64_linux.tar.gz scion-pki
31+
- uses: netsys-lab/setup-composite@feature/ci
32+
- name: Compile Examples
33+
run: |
34+
source development.env
35+
export PATH=$PATH:$PWD/bin
36+
tests/compile-and-build-test/compile-test.py
37+
38+
run-tests:
39+
name: Run Tests
40+
needs: compile-examples # Only run heavy tests if quick compile test succeeds
41+
runs-on: ubuntu-latest
42+
permissions:
43+
contents: read
44+
steps:
45+
- name: Check out the source repository
46+
uses: actions/checkout@v4
47+
- name: Set up Python
48+
uses: actions/setup-python@v5
49+
with:
50+
python-version: "3.10"
51+
cache: 'pip'
52+
cache-dependency-path: "**/*requirements.txt"
53+
- run: pip install -r requirements.txt -r dev-requirements.txt -r tests/requirements.txt
54+
- name: Get scion-pki
55+
run: |
56+
curl -fsSL -O https://github.com/scionproto/scion/releases/download/v0.12.0/scion_0.12.0_amd64_linux.tar.gz
57+
mkdir bin
58+
tar -C bin -xzf scion_0.12.0_amd64_linux.tar.gz scion-pki
59+
- name: Run tests
60+
run: |
61+
source development.env
62+
export PATH=$PATH:$PWD/bin
63+
tests/run-tests.py --ci
64+
- name: Archive test results
65+
uses: actions/upload-artifact@v4
66+
with:
67+
name: test_result
68+
path: |
69+
tests/test_result.txt
70+
tests/**/test_log
71+
- name: Check for errors
72+
shell: bash
73+
run: grep -E "^score" tests/test_result.txt | grep -Eq '[1-9][0-9]* errors|[1-9][0-9]* failures'; test $? -gt 1
74+
75+
build-examples:
76+
name: Build Examples
77+
needs: compile-examples # Only run heavy tests if quick compile test succeeds
78+
runs-on: ubuntu-latest
79+
permissions:
80+
contents: read
81+
steps:
82+
- name: Check out the source repository
83+
uses: actions/checkout@v4
84+
- name: Set up Python
85+
uses: actions/setup-python@v5
86+
with:
87+
python-version: "3.10"
88+
cache: 'pip'
89+
cache-dependency-path: "**/*requirements.txt"
90+
- run: pip install -r requirements.txt -r dev-requirements.txt -r tests/requirements.txt
91+
- name: Get scion-pki
92+
run: |
93+
curl -fsSL -O https://github.com/scionproto/scion/releases/download/v0.12.0/scion_0.12.0_amd64_linux.tar.gz
94+
mkdir bin
95+
tar -C bin -xzf scion_0.12.0_amd64_linux.tar.gz scion-pki
96+
- name: Build Examples
97+
run: |
98+
source development.env
99+
export PATH=$PATH:$PWD/bin
100+
cd tests/compile-and-build-test
101+
./compile-and-build-test.py
102+
- name: Archive test results
103+
uses: actions/upload-artifact@v4
104+
with:
105+
name: test_log
106+
path: |
107+
tests/compile-and-build-test/test_log/build_log.txt
108+
tests/compile-and-build-test/test_log/log.txt
109+
- name: Check for errors
110+
shell: bash
111+
run: grep -E "^score" tests/compile-and-build-test/test_log/log.txt | grep -Eq '[1-9][0-9]* errors|[1-9][0-9]* failures'; test $? -gt 1
File renamed without changes.
File renamed without changes.

examples/scion/S05_scion_internet/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ server in each IX enabling full multilateral peering.
2020

2121
```bash
2222
./bgp-internet.py
23-
cd bgp
23+
cd output/bgp
2424
docker-compose build
2525
docker-compose up -d
2626
```
@@ -47,7 +47,7 @@ provider and access networks of different sizes.
4747

4848
```bash
4949
./scion-internet.py
50-
cd scion
50+
cd output/scion
5151
docker-compose build
5252
docker compose up -d # use docker compose v2 (no hyphen)
5353
```

examples/scion/S05_scion_internet/bgp_internet.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env python3
22

3+
import os
34
from ipaddress import IPv4Network
45
from seedemu.compiler import Docker
56
from seedemu.core import Emulator
@@ -173,4 +174,5 @@ def next_addr(self, net):
173174
emu.render()
174175

175176
# Compilation
176-
emu.compile(Docker(), './bgp')
177+
os.makedirs('./output', exist_ok=True)
178+
emu.compile(Docker(), './output/bgp')

examples/scion/S05_scion_internet/scion_internet.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#!/usr/bin/env python3
22

3+
import os
34
from ipaddress import IPv4Network
45
from seedemu.compiler import Docker
56
from seedemu.core import Emulator
@@ -296,4 +297,5 @@ def next_addr(self, net):
296297
emu.render()
297298

298299
# Compilation
299-
emu.compile(Docker(), './scion')
300+
os.makedirs('./output', exist_ok=True)
301+
emu.compile(Docker(), './output/scion')

requirements.txt

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,49 @@
1-
eth_account==0.5.9
1+
aiohappyeyeballs==2.4.6
2+
aiohttp==3.11.13
3+
aiosignal==1.3.2
4+
async-timeout==5.0.1
5+
attrs==25.1.0
6+
base58==2.1.1
7+
bitarray==2.9.3
8+
certifi==2025.1.31
9+
chardet==3.0.4
10+
cytoolz==0.12.3
11+
docker==4.1.0
12+
eth-abi==2.2.0
13+
eth-account==0.5.9
14+
eth-hash==0.7.1
15+
eth-keyfile==0.5.1
16+
eth-keys==0.3.4
217
eth-rlp<0.3
3-
PyYAML==6.0.1
18+
eth-typing==2.3.0
19+
eth-utils==1.9.5
20+
Faker==24.4.0
21+
frozenlist==1.5.0
22+
hexbytes==0.3.1
23+
idna==2.8
24+
ipfshttpclient==0.8.0a2
25+
jsonschema==4.23.0
26+
jsonschema-specifications==2024.10.1
27+
lru-dict==1.3.0
28+
multiaddr==0.0.9
29+
multidict==6.1.0
30+
netaddr==1.3.0
31+
parsimonious==0.8.1
32+
propcache==0.3.0
33+
protobuf==3.19.5
34+
pycryptodome==3.21.0
35+
python-dateutil==2.9.0.post0
36+
PyYAML==6.0.2
37+
referencing==0.36.2
438
requests==2.22.0
39+
rlp==2.0.1
40+
rpds-py==0.23.1
41+
six==1.17.0
42+
toolz==1.0.0
43+
typing_extensions==4.12.2
44+
urllib3==1.25.11
45+
varint==1.0.2
546
web3==5.31.1
47+
websocket-client==1.8.0
48+
websockets==9.1
49+
yarl==1.18.3

seedemu/layers/Ebgp.py

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,13 @@ def __createPeer(self, nodeA: Router, nodeB: Router, addrA: str, addrB: str, rel
8686
if node.getRole() == NodeRole.RouteServer:
8787
rsNode = node
8888
continue
89-
89+
9090
if routerA == None: routerA = node
9191
elif routerB == None: routerB = node
9292

9393
if not node.getAttribute('__bgp_bootstrapped', False):
9494
self._log('Bootstrapping as{}/{} for BGP...'.format(node.getAsn(), node.getName()))
95-
95+
9696
node.setAttribute('__bgp_bootstrapped', True)
9797
node.appendFile('/etc/bird/bird.conf', EbgpFileTemplates['bgp_commons'].format(localAsn = node.getAsn()))
9898

@@ -129,7 +129,7 @@ def __createPeer(self, nodeA: Router, nodeB: Router, addrA: str, addrB: str, rel
129129
))
130130

131131
return
132-
132+
133133
if rel == PeerRelationship.Peer:
134134
routerA.addProtocol('bgp', 'p_as{}'.format(routerB.getAsn()), EbgpFileTemplates["rnode_bird_peer"].format(
135135
localAddress = addrA,
@@ -191,7 +191,7 @@ def __createPeer(self, nodeA: Router, nodeB: Router, addrA: str, addrB: str, rel
191191
exportFilter = "all",
192192
importCommunity = "PROVIDER_COMM",
193193
bgpPref = 10
194-
))
194+
))
195195

196196
def getName(self) -> str:
197197
return "Ebgp"
@@ -262,7 +262,7 @@ def addCrossConnectPeering(self, a: int, b: int, abRelationship: PeerRelationshi
262262
B. Default to Peer.
263263
264264
@throws AssertionError if peering already exist.
265-
265+
266266
@returns self, for chaining API calls.
267267
"""
268268
assert (a, b) not in self.__xc_peerings, '{} <-> {} already configured as XC peer'.format(a, b)
@@ -320,7 +320,7 @@ def getRsPeers(self) -> List[Tuple[int, int]]:
320320
321321
@returns list of tuple of (ix, peerAsn)
322322
"""
323-
return self.__rs_peers
323+
return self.__rs_peers
324324

325325
def configure(self, emulator: Emulator) -> None:
326326
reg = emulator.getRegistry()
@@ -365,7 +365,7 @@ def configure(self, emulator: Emulator) -> None:
365365

366366
for node in a_reg.getByType('rnode'):
367367
router: Router = node
368-
for (peername, peerasn), (localaddr, _) in router.getCrossConnects().items():
368+
for (peername, peerasn), (localaddr, _, _) in router.getCrossConnects().items():
369369
if peerasn != b: continue
370370
if not b_reg.has('rnode', peername): continue
371371

@@ -374,7 +374,7 @@ def configure(self, emulator: Emulator) -> None:
374374
b_router = b_reg.get('rnode', peername)
375375

376376
a_addr = str(localaddr.ip)
377-
(b_ifaddr, _) = b_router.getCrossConnect(a, a_router.getName())
377+
(b_ifaddr, _, _) = b_router.getCrossConnect(a, a_router.getName())
378378
b_addr = str(b_ifaddr.ip)
379379

380380
break
@@ -404,7 +404,7 @@ def configure(self, emulator: Emulator) -> None:
404404
a_ixnode = node
405405
a_ixif = iface
406406
break
407-
407+
408408
assert a_ixnode != None, 'cannot resolve peering: as{} not in ix{}'.format(a, ix)
409409

410410
b_ixnode: Router = None
@@ -416,7 +416,7 @@ def configure(self, emulator: Emulator) -> None:
416416
b_ixnode = node
417417
b_ixif = iface
418418
break
419-
419+
420420
assert b_ixnode != None, 'cannot resolve peering: as{} not in ix{}'.format(b, ix)
421421

422422
self._log("adding IX peering: {} as {} <-({})-> {} as {}".format(a_ixif.getAddress(), a, rel, b_ixif.getAddress(), b))
@@ -443,10 +443,10 @@ def _doCreateGraphs(self, emulator: Emulator):
443443
ix_graph = self._addGraph('IX{} Peering Sessions'.format(ix), False)
444444

445445
mesh_ases = set()
446-
446+
447447
for (i, a) in self.__rs_peers:
448448
if i == ix: mesh_ases.add(a)
449-
449+
450450
self._log('IX{} RS-mesh: {}'.format(ix, mesh_ases))
451451

452452
while len(mesh_ases) > 0:
@@ -463,7 +463,7 @@ def _doCreateGraphs(self, emulator: Emulator):
463463

464464
full_graph.addEdge('AS{}'.format(a), 'AS{}'.format(b), 'IX{}'.format(ix), 'IX{}'.format(ix), style = 'dashed', alabel = 'R', blabel= 'R')
465465
ix_graph.addEdge('AS{}'.format(a), 'AS{}'.format(b), 'IX{}'.format(ix), 'IX{}'.format(ix), style = 'dashed', alabel = 'R', blabel= 'R')
466-
466+
467467
for (i, a, b), rel in self.__peerings.items():
468468
self._log('Creating private peering sessions graph for IX{} AS{} <-> AS{}...'.format(i, a, b))
469469

@@ -483,7 +483,7 @@ def _doCreateGraphs(self, emulator: Emulator):
483483
full_graph.addEdge('AS{}'.format(a), 'AS{}'.format(b), 'IX{}'.format(i), 'IX{}'.format(i), alabel = 'P', blabel= 'P')
484484
ix_graph.addEdge('AS{}'.format(a), 'AS{}'.format(b), 'IX{}'.format(i), 'IX{}'.format(i), alabel = 'P', blabel= 'P')
485485

486-
if rel == PeerRelationship.Provider:
486+
if rel == PeerRelationship.Provider:
487487
full_graph.addEdge('AS{}'.format(a), 'AS{}'.format(b), 'IX{}'.format(i), 'IX{}'.format(i), alabel = 'U', blabel = 'C')
488488
ix_graph.addEdge('AS{}'.format(a), 'AS{}'.format(b), 'IX{}'.format(i), 'IX{}'.format(i), alabel = 'U', blabel = 'C')
489489

@@ -516,4 +516,3 @@ def print(self, indent: int) -> str:
516516

517517

518518
return out
519-

0 commit comments

Comments
 (0)