Skip to content

Commit

Permalink
Merge pull request #82 from GaloisInc/42-mps-tests-in-ci
Browse files Browse the repository at this point in the history
ci: run MPS tests against OpenSUT VMs

Adds a script that starts up the host and guest VMs, with MPS running in the guest, and runs the MPS test suite against that setup.  Also adds a CI job to run this script.
  • Loading branch information
spernsteiner authored Jul 2, 2024
2 parents 67d25c4 + b65fa29 commit 9c3c268
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 1 deletion.
32 changes: 32 additions & 0 deletions .github/workflows/main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -285,3 +285,35 @@ jobs:
bash src/pkvm_setup/package.sh full_build vm_images
outputs:
CACHE_KEY: ${{ steps.hash.outputs.CACHE_KEY }}

mps-test-vm:
runs-on: ubuntu-22.04
needs:
- mps-build
- vm_images
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Download MPS binaries
uses: actions/download-artifact@v4
with:
name: mps-binaries
- name: Prepare MPS binaries for use
run: |
chmod +x rts.*
mv rts.* components/mission_protection_system/src/.
- name: "Cache restore: vm_images"
uses: actions/cache/restore@v3
with:
key: ${{ needs.vm_images.outputs.CACHE_KEY }}
path: packages/${{ needs.vm_images.outputs.CACHE_KEY }}.tar.gz
- name: "Unpack vm_images"
run: |
tar -xvf packages/${{ needs.vm_images.outputs.CACHE_KEY }}.tar.gz
- name: Install QEMU
run: sudo apt-get install -y qemu-system-arm
- uses: hecrj/setup-rust-action@v2
with:
rust-version: 1.74
- name: Run MPS tests
run: RUST_LOG=trace RTS_DEBUG=1 python3 src/vm_runner/tests/mps/run_tests.py
2 changes: 1 addition & 1 deletion components/mission_protection_system/tests/runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
RTS_SOCKET = os.environ.get("RTS_SOCKET")
RTS_DEBUG = os.environ.get("RTS_DEBUG") is not None

def try_expect(p,expected,timeout=10,retries=10):
def try_expect(p,expected,timeout=60,retries=10):
expected = expected.strip()
if RTS_DEBUG:
print(f"CHECKING: {expected}")
Expand Down
84 changes: 84 additions & 0 deletions src/vm_runner/tests/mps/run_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import os
import select
import socket
import subprocess
import time

CONFIG_DIR = os.path.abspath(os.path.dirname(__file__))
VM_RUNNER_DIR = os.path.join(CONFIG_DIR, '../..')
TESTS_DIR = os.path.join(CONFIG_DIR, '../../../../components/mission_protection_system/tests')

def main():
proc_vm = None
try:
rts_socket = os.path.join(VM_RUNNER_DIR, 'serial.socket')

print('run_tests.py: build application images')
subprocess.run(
('bash', os.path.join(CONFIG_DIR, 'build_img.sh')),
cwd = VM_RUNNER_DIR,
check = True,
)

print('run_tests.py: build vm_runner')
subprocess.run(
('cargo', 'build'),
cwd = VM_RUNNER_DIR,
check = True,
)

print('run_tests.py: start VM')
proc_vm = subprocess.Popen(
('cargo', 'run', '--', os.path.join(CONFIG_DIR, 'base_nested.toml')),
cwd = VM_RUNNER_DIR,
# Prevent the VM process from intercepting ^C.
stdin = subprocess.DEVNULL,
)

# Wait for VM startup. We detect startup by listening on the secondary
# serial port for the MPS to send some output.
print('run_tests.py: waiting for serial.socket')
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
for _ in range(10):
try:
sock.connect(rts_socket)
break
except OSError:
pass
time.sleep(1)
print('run_tests.py: waiting for data on serial.socket')
sock.settimeout(300)
sock.recv(1)
sock.close()

# Run the test suite.
print('run_tests.py: run test suite')
subprocess.run(
('python3', 'run_all.py'),
cwd = TESTS_DIR,
env = {
'RTS_SOCKET': rts_socket,
'QUICK': '1',
**os.environ
},
check = True,
)

# Signal the MPS to shut down.
print('run_tests.py: shut down MPS')
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
sock.connect(rts_socket)
sock.send(b'Q\r\n')
sock.close()

# Wait for the VM to terminate.
print('run_tests.py: wait for VM to exit')
proc_vm.wait(timeout = 300)
assert proc_vm.returncode == 0
proc_vm = None
finally:
if proc_vm is not None and proc_vm.returncode is None:
proc_vm.kill()

if __name__ == '__main__':
main()

0 comments on commit 9c3c268

Please sign in to comment.