Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial Regression Test Release #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions regression-tests/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
*.pyc
*_string_matches.txt
*.exe
*.elf
41 changes: 41 additions & 0 deletions regression-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# PANDA Regression Tests

These tests are intended to be full system tests for PANDA.

# Running the Tests

1. Run the included test data download script to obtain the entire test data
set.

```
TODO
```

2. Setup a virtualenv with the Python dependencies used for testing.

```
python3 -m virtualenv -p /usr/bin/python3 env
. ./env/bin/activate
pip3 install -r requirements.txt
```

3. Execute the tests.

```
./run.py /path/to/PANDA/build/folder /path/to/folder/containing/test/data
```

4. Once you've run the tests, you can deactivate the virtualenv.

```
deactivate
```

# Adding Tests

Adding tests to the regression test suite is easy. Just create a new Python
module under the tests directory with the prefix `test_`. The test framework
will automatically resolve tests.

A test must have a `run` and `cleanup` method. `run` returns true if the test
passes or false if it fails. Refer to the examples directory.
13 changes: 13 additions & 0 deletions regression-tests/examples/dummy/test_example.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import ptest

def run():
"""
This is where you will actually perform the steps of the test. If the test passes, return True. Otherwise return False.
"""
return True

def cleanup():
"""
This function is called after the test executes regardless of whether or not the test succeeded. You should clean up any temporary files if any.
"""
pass
7 changes: 7 additions & 0 deletions regression-tests/ptest/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
from ptest.plogreader import *
from ptest.plugin import *
from ptest.qemu import *
from ptest.replay import *
from ptest.runlive import *
from ptest.testexec import *
from ptest.utils import *
81 changes: 81 additions & 0 deletions regression-tests/ptest/plogreader.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import importlib
import struct
import zlib

def get_plog_pb2():
"""
plog_pb2 comes with PANDA, but we don't know WHICH PANDA at the time this
class is loaded (that is set up in the run.py file). So, load plog_pb2
dynamically, as the paths to find it will be set by the time need it.
(This was Nathan Jackson's idea - thank you very much.)
"""
return importlib.import_module("plog_pb2")

class PlogReader:
"""
Provide facilities to read a PANDA log file using an iterator.
"""

def __init__(self, fn):
self.f = open(fn, mode='rb')
self.version, _, self.dir_pos, _, self.chunk_gsize = struct.unpack('<IIQII', self.f.read(24))

self.f.seek(self.dir_pos)
self.nchunks, = struct.unpack('<I', self.f.read(4)) # number of chunks
self.chunks = self.f.read(24*self.nchunks) # chunks buffer
self.chunk_idx = 0 # index of current chunk
self.chunk_size = 0 # size of current chunk
self.chunk_data = None # data of current chunk
self.chunk_data_idx = 0

def __iter__(self):
return self

def __enter__(self):
return self

def __exit__(self, exc_type, exc_val, exc_tb):
self.f.close()
self.f = self.chunk_data = None

def __next__(self):
# ran out of chunks
if not self.chunk_idx < self.nchunks:
raise StopIteration

if self.chunk_data is None:
# unpack ins, pos, nentries for this and the next chunk
cur = struct.unpack_from('<QQQ', self.chunks, 24*self.chunk_idx)
if self.chunk_idx + 1 < self.nchunks:
nxt = struct.unpack_from('<QQQ', self.chunks, 24*(self.chunk_idx+1))
zchunk_size = nxt[1] - cur[1]
else:
# setting the compressed chunk size to -1 will
# result in reading the remaining of the file
zchunk_size = -1

# read and decompress chunk data
self.f.seek(cur[1])
self.chunk_data = zlib.decompress(self.f.read(zchunk_size), 15, self.chunk_gsize)
self.chunk_size = len(self.chunk_data)
self.chunk_data_idx = 0

# parse message - we're using a fresh message
# using MergeFromString() is slightly faster than using ParseFromString()
msg_size, = struct.unpack_from('<I', self.chunk_data, self.chunk_data_idx)
msg = get_plog_pb2().LogEntry()
msg_start = self.chunk_data_idx + 4
msg_end = msg_start + msg_size
msg.MergeFromString(self.chunk_data[msg_start:msg_end])

# update state
self.chunk_data_idx = msg_end

if not self.chunk_data_idx < self.chunk_size:
self.chunk_idx += 1
self.chunk_size = 0
self.chunk_data = None
self.chunk_data_idx = 0

return msg

36 changes: 36 additions & 0 deletions regression-tests/ptest/plugin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class Plugin:
def __init__(self, plugin_name, **kwargs):
"""
Constructs a new plugin with the specified name, validation function,
and arguments.
"""
self.name = plugin_name
self.args = {}
for key, value in kwargs.items():
self.args[key] = value

def cmdline(self):
"""
Renders the plugin's command-line option as to be passed to PANDA.
"""

arg_str = self.name
if self.args:
arg_str += ':'
args = []
for key in self.args:
value = self.args[key]
args.append('%s=%s' % (key, value))
arg_str += ",".join(args)

cmdline = ["-panda", arg_str]
return cmdline

# These are just some tests I was running.
if __name__ == "__main__":
plugin = Plugin("stringsearch", str="hello world")
print(plugin.cmdline())
plugin = Plugin("stringsearch", name="test")
print(plugin.cmdline())
plugin = Plugin("asidstory")
print(plugin.cmdline())
Loading