Commit dbfb93c8 authored by williangaspar's avatar williangaspar Committed by Matheus Marchini
parent 4bb86107
build/
build-*/
tests/runtime/*.pyc
......@@ -70,3 +70,10 @@ target_link_libraries(bpftrace_test ${binary_dir}/googlemock/libgmock.a)
target_link_libraries(bpftrace_test ${CMAKE_THREAD_LIBS_INIT})
add_test(NAME bpftrace_test COMMAND bpftrace_test)
configure_file(runtime-tests.sh runtime-tests.sh COPYONLY)
configure_file(main.py main.py COPYONLY)
configure_file(parser.py parser.py COPYONLY)
configure_file(utils.py utils.py COPYONLY)
file(COPY runtime DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
add_custom_target(runtime-tests COMMAND ./runtime-tests.sh)
# BPFtrace Tests
Tests can be run with the `bpftrace_test` executable.
There are two test suites in the project.
## Unit tests
These tests can be run with the `bpftrace_test` executable.
The code generation tests are based on the output of LLVM 5, so may give errors if run with different version. They can be excluded by running:
`bpftrace_test --gtest_filter=-codegen*`
## Runtime tests
Runtime tests will call the bpftrace executable.
* Run: `sudo make runtime-tests` inside your build folder
* By default, runtime-tests will look for the executable in the build folder. You can set a value to the environment variable `BPFTRACE_RUNTIME_TEST_EXECUTABLE` to customize it
#!/usr/bin/python
import os
from os import environ
import time
from datetime import timedelta
from utils import Utils
from parser import TestParser
def main():
test_suite = TestParser.read_all()
start_time = time.time()
total_tests = 0
total_fail = 0
for fname, tests in test_suite:
print('Test file: ' + fname + '\n')
for test in tests:
success = Utils.run_test(test)
total_tests += 1
if not success:
total_fail += 1
print('--------------------------------\n')
elapsed = time.time() - start_time
print(str(total_tests) + ' tests [fail ' + str(total_fail) + ']')
print('Done in ' + str(timedelta(seconds=elapsed)) )
if __name__ == "__main__":
main()
#!/usr/bin/python
from collections import namedtuple
import os
from utils import ERROR_COLOR, NO_COLOR
class RequiredFieldError(Exception):
pass
TestStruct = namedtuple('TestStruct', 'name run expect timeout before after')
class TestParser(object):
@staticmethod
def read_all():
try:
for root, _, files in os.walk('./runtime'):
for filename in files:
yield TestParser.read(root + '/' + filename)
except RequiredFieldError as error:
print(ERROR_COLOR + str(error) + NO_COLOR)
@staticmethod
def read(file_name):
tests = []
test_lines = []
with open (file_name, 'r') as file:
for line in file.readlines():
if line != '\n':
test_lines.append(line)
else:
tests.append(TestParser.__read_test_struct(test_lines, file_name))
test_lines = []
tests.append(TestParser.__read_test_struct(test_lines, file_name))
return (file_name.split('/')[-1], tests)
@staticmethod
def __read_test_struct(test, file_name):
name = ''
run = ''
expect = ''
timeout = ''
before = ''
after = ''
for item in test:
item_split = item.split()
item_name = item_split[0]
line = ' '.join(item_split[1:])
if item_name == 'NAME':
name = line
elif item_name == 'RUN':
run = line
elif item_name == 'EXPECT':
expect = line
elif item_name == 'TIMEOUT':
timeout = int(line.strip(' '))
elif item_name == 'BEFORE':
before = line
elif item_name == 'AFTER':
after = line
if name == '':
raise RequiredFieldError('Test NAME is required. File: ' + file_name)
elif run == '':
raise RequiredFieldError('Test RUN is required. File: ' + file_name)
elif expect == '':
raise RequiredFieldError('Test EXPECT is required. File: ' + file_name)
elif timeout == '':
raise RequiredFieldError('Test TIMEOUT is required. File: ' + file_name)
return TestStruct(name, run, expect, timeout, before, after)
#!/bin/bash
set -e;
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null && pwd )"
BPFTRACE_RUNTIME_TEST_EXECUTABLE=${BPFTRACE_RUNTIME_TEST_EXECUTABLE:-$DIR/../src/};
export BPFTRACE_RUNTIME_TEST_EXECUTABLE;
python main.py;
NAME pid
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", pid); exit(); }'
EXPECT SUCCESS pid [0-9][0-9]*
TIMEOUT 5
NAME tid
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", tid); exit(); }'
EXPECT SUCCESS tid [0-9][0-9]*
TIMEOUT 5
NAME uid
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", uid); exit(); }'
EXPECT SUCCESS uid [0-9][0-9]*
TIMEOUT 5
NAME gid
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", gid); exit(); }'
EXPECT SUCCESS gid [0-9][0-9]*
TIMEOUT 5
NAME nsecs
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", nsecs); exit(); }'
EXPECT SUCCESS nsecs -?[0-9][0-9]*
TIMEOUT 5
NAME cpu
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", cpu); exit(); }'
EXPECT SUCCESS cpu -?[0-9][0-9]*
TIMEOUT 5
NAME comm
RUN bpftrace -e 'k:do_nanosleep { printf("SUCCESS '$test' %s\n", comm); exit(); }'
EXPECT SUCCESS comm .*
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
AFTER | egrep 'SUCCESS comm .*'
NAME stack
RUN bpftrace -e 'k:do_nanosleep { printf("SUCCESS '$test' %s\n", stack); exit(); }'
EXPECT SUCCESS stack
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME ustack
RUN bpftrace -e 'k:do_nanosleep { printf("SUCCESS '$test' %s\n", ustack); exit(); }'
EXPECT SUCCESS ustack
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME arg
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", arg0); exit(); }'
EXPECT SUCCESS arg -?[0-9][0-9]*
TIMEOUT 5
NAME retval
RUN bpftrace -e 'k:do_nanosleep { printf("SUCCESS '$test' %d\n", retval); exit(); }'
EXPECT SUCCESS retval .*
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME func
RUN bpftrace -e 'k:do_nanosleep { printf("SUCCESS '$test' %s\n", func); exit(); }'
EXPECT SUCCESS func .*
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME username
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %s\n", username); exit(); }'
EXPECT SUCCESS username .*
TIMEOUT 5
NAME probe
RUN bpftrace -e 'k:do_nanosleep { printf("SUCCESS '$test' %s\n", probe); exit(); }'
EXPECT SUCCESS probe kprobe:do_nanosleep
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME curtask
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", curtask); exit(); }'
EXPECT SUCCESS curtask -?[0-9][0-9]*
TIMEOUT 5
NAME rand
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", rand); exit(); }'
EXPECT SUCCESS rand -?[0-9][0-9]*
TIMEOUT 5
NAME cgroup
RUN bpftrace -e 'i:ms:1 { printf("SUCCESS '$test' %d\n", cgroup); exit(); }'
EXPECT SUCCESS cgroup -?[0-9][0-9]*
TIMEOUT 5
NAME printf
RUN bpftrace -e 'i:ms:1 { printf("hi!\n"); exit();}'
EXPECT hi!
TIMEOUT 5
NAME printf_argument
RUN bpftrace -e 'i:ms:1 { printf("value: %d100\n", 100); exit();}'
EXPECT value: 100
TIMEOUT 5
NAME time
RUN bpftrace -e 'i:ms:1 { time("%H:%M:%S\n"); exit();}'
EXPECT [0-9]*:[0-9]*:[0-9]*
TIMEOUT 5
NAME time_short
RUN bpftrace -e 'i:ms:1 { time("%H-%M:%S\n"); exit();}'
EXPECT [0-9]*-[0-9]*
TIMEOUT 5
NAME join
RUN bpftrace -e 'i:ms:1 { system("echo 'A'"); } kprobe:sys_execve { join(arg1); exit();}'
EXPECT A
TIMEOUT 5
NAME str
RUN bpftrace -e 'i:ms:1 { system("echo 10"); } k:sys_execve { printf("P: %s\n", str(arg0)); exit();}'
EXPECT P: /bin/sh
TIMEOUT 5
NAME sym
RUN bpftrace -e 'kprobe:do_nanosleep { printf("%s\n", sym(reg("ip"))); exit();}'
EXPECT P: /bin/sh
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME system
RUN bpftrace -e 'i:ms:1 { system("echo 'ok_system'"); exit();}'
EXPECT ok_system
TIMEOUT 5
NAME count
RUN bpftrace -e 'i:ms:100 { @[sym(reg("ip"))] = count(); exit();}'
EXPECT @\[[0-9]*\]\:\s[0-9]*
TIMEOUT 5
NAME sum
RUN bpftrace -e 'kprobe:vfs_read { @bytes[comm] = sum(arg2); exit();}'
EXPECT @.*\[.*\]\:\s[0-9]*
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME avg
RUN bpftrace -e 'kprobe:vfs_read { @bytes[comm] = avg(arg2); exit();}'
EXPECT @.*\[.*\]\:\s[0-9]*
TIMEOUT 5
NAME min
RUN bpftrace -e 'kprobe:vfs_read { @bytes[comm] = min(arg2); exit();}'
EXPECT @.*\[.*\]\:\s[0-9]*
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME max
RUN bpftrace -e 'kprobe:vfs_read { @bytes[comm] = max(arg2); exit();}'
EXPECT @.*\[.*\]\:\s[0-9]*
TIMEOUT 5
NAME stats
RUN bpftrace -e 'kprobe:vfs_read { @bytes[comm] = stats(arg2); exit();}'
EXPECT @.*\[.*\]\:\scount\s[0-9]*\,\saverage\s[0-9]*\,\stotal\s[0-9]*
TIMEOUT 5
NAME hist
RUN bpftrace -e 'kretprobe:vfs_read { @bytes = hist(retval); exit();}'
EXPECT @bytes:\s\n\n\[.*\,\s.*\]?\)?\s
TIMEOUT 5
NAME lhist
RUN bpftrace -e 'kretprobe:vfs_read { @bytes = lhist(retval, 0, 10000, 1000); exit()}'
EXPECT @bytes:\s\n\n\(?\[?.*
TIMEOUT 5
NAME if_gt
RUN bpftrace -e 'i:ms:1 {$a = 10; if ($a > 2) { $a = 20 }; printf("a=%d\n", $a); exit();}'
EXPECT a=20
TIMEOUT 5
NAME if_lt
RUN bpftrace -e 'i:ms:1 {$a = 10; if ($a < 2) { $a = 20 }; printf("a=%d\n", $a); exit();}'
EXPECT a=10
TIMEOUT 5
NAME ifelse_go_else
RUN bpftrace -e 'i:ms:1 {$a = ""; if (10 < 2) { $a = "hi" } else {$a = "hello"}; printf("a=%s\n", $a); exit();}'
EXPECT a=hello
TIMEOUT 5
NAME ifelse_go_if
RUN bpftrace -e 'i:ms:1 {$a = ""; if (10 > 2) { $a = "hi" } else {$a = "hello"}; printf("a=%s\n", $a); exit();}'
EXPECT a=hi
TIMEOUT 5
NAME unroll
RUN bpftrace -e 'i:ms:1 {$a = 1; unroll (10) { $a = $a + 1; }; printf("a=%d\n", $a); exit();}'
EXPECT a=11
TIMEOUT 5
NAME unroll_max_value
RUN bpftrace -e 'i:ms:1 {$a = 1; unroll (30) { $a = $a + 2; }; printf("a=%d\n", $a); exit();}'
EXPECT unroll maximum value is 20
TIMEOUT 5
NAME unroll_min_value
RUN bpftrace -e 'i:ms:1 {$a = 1; unroll (0) { $a = $a + 2; }; printf("a=%d\n", $a); exit();}'
EXPECT unroll minimum value is 1
TIMEOUT 5
NAME kprobe
RUN bpftrace -e 'kprobe:do_nanosleep { printf("SUCCESS '$test' %d\n", pid); exit(); }'
EXPECT SUCCESS kprobe [0-9][0-9]*
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME kprobe_short_name
RUN bpftrace -e 'k:do_nanosleep { printf("SUCCESS '$test' %d\n", pid); exit(); }'
EXPECT SUCCESS kprobe_short_name [0-9][0-9]*
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME kprobe_target
RUN bpftrace -e 'kprobe:syscalls:sys_exit_nanosleep { printf("SUCCESS '$test' %d\n", pid); exit(); }'
EXPECT kprobes should not have a target
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME kretprobe
RUN bpftrace -e 'kretprobe:do_nanosleep { printf("SUCCESS '$test' %d\n", pid); exit(); }'
EXPECT SUCCESS kretprobe [0-9][0-9]*
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME kretprobe_short_name
RUN bpftrace -e 'kr:do_nanosleep { printf("SUCCESS '$test' %d\n", pid); exit(); }'
EXPECT SUCCESS kretprobe_short_name [0-9][0-9]*
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
NAME kretprobe_target
RUN bpftrace -e 'kretprobe:syscalls:sys_exit_nanosleep { printf("SUCCESS '$test' %d\n", pid); exit(); }'
EXPECT kprobes should not have a target
TIMEOUT 5
NAME uprobe
RUN bpftrace -e 'uprobe:/bin/bash:echo_builtin { printf("arg0: %d", arg0); exit();}'
EXPECT arg0: [0-9]*
TIMEOUT 5
BEFORE (sleep 1; /bin/bash -c echo) &
NAME uretprobe
RUN bpftrace -e 'uretprobe:/bin/bash:echo_builtin { printf("readline: %d\n", retval); exit();}'
EXPECT readline: [0-9]*
TIMEOUT 5
BEFORE (sleep 1; /bin/bash -c echo) &
NAME tracepoint
RUN bpftrace -e 'tracepoint:syscalls:sys_exit_nanosleep { printf("SUCCESS '$test' %d\n", gid); exit(); }'
EXPECT SUCCESS tracepoint [0-9][0-9]*
TIMEOUT 5
NAME tracepoint_short_name
RUN bpftrace -e 't:syscalls:sys_exit_nanosleep { printf("SUCCESS '$test' %d\n", gid); exit(); }'
EXPECT SUCCESS tracepoint_short_name [0-9][0-9]*
TIMEOUT 5
NAME profile
RUN bpftrace -e 'profile:hz:99 { @[tid] = count(); exit();}'
EXPECT \@\[[0-9]*\]\:\s[0-9]
TIMEOUT 5
NAME profile_short_name
RUN bpftrace -e 'p:hz:99 { @[tid] = count(); exit();}'
EXPECT \@\[[0-9]*\]\:\s[0-9]
TIMEOUT 5
NAME interval
RUN bpftrace -e 't:raw_syscalls:sys_enter { @syscalls = count(); } interval:s:1{ print(@syscalls); clear(@syscalls); exit();}'
EXPECT @syscalls\:\s[0-9]*
TIMEOUT 5
NAME interval_short_name
RUN bpftrace -e 't:raw_syscalls:sys_enter { @syscalls = count(); } i:s:1{ print(@syscalls); clear(@syscalls); exit();}'
EXPECT @syscalls\:\s[0-9]*
TIMEOUT 5
NAME software
RUN bpftrace -e 'software:faults:100 { @[comm] = count(); exit();}'
EXPECT @\[.*\]\:\s[0-9]*
TIMEOUT 5
NAME hardware
RUN bpftrace -e 'hardware:cache-misses:1000000 { @[pid] = count(); exit(); }'
EXPECT @\[.*\]\:\s[0-9]*
TIMEOUT 5
NAME BEGIN
RUN bpftrace -e 'BEGIN { printf("Hello\n"); exit();}'
EXPECT Hello
TIMEOUT 2
NAME global_int
RUN bpftrace -e 'i:ms:1 {@a = 10; printf("%d\n", @a); exit();}'
EXPECT \@a: 10
TIMEOUT 5
NAME global_string
RUN bpftrace -e 'i:ms:1 {@a = "hi"; printf("%s\\n", @a); exit();}'
EXPECT @a: hi
TIMEOUT 5
NAME local_int
RUN bpftrace -e 'i:ms:1 {$a = 10; printf("a=%d\n", $a); exit();}'
EXPECT a=10
TIMEOUT 5
NAME local_string
RUN bpftrace -e 'i:ms:1 {$a = "hi"; printf("a=%s\n", $a); exit();}'
EXPECT a=hi
TIMEOUT 5
NAME global_associative_arrays
RUN bpftrace -e 'k:do_nanosleep { @start[tid] = nsecs; } kretprobe:do_nanosleep /@start[tid] != 0/ { printf("slept for %d ms\n", (nsecs - @start[tid]) / 1000000); delete(@start[tid]); exit();}'
EXPECT slept for [0-9]+ ms
TIMEOUT 5
BEFORE (sleep 1; sleep 1) &
NAME scratch
RUN bpftrace -e 'k:do_nanosleep { @start[tid] = nsecs; } kretprobe:do_nanosleep /@start[tid] != 0/ { $delta = nsecs - @start[tid]; printf("slept for %d ms\n", $delta / 1000000); delete(@start[tid]); exit(); }'
EXPECT slept for [0-9]* ms
TIMEOUT 5
BEFORE sleep 1 && sleep 1 &
import subprocess
import signal
import sys
from os import environ
import re
BPF_PATH = environ["BPFTRACE_RUNTIME_TEST_EXECUTABLE"]
OK_COLOR = '\033[92m'
ERROR_COLOR = '\033[91m'
NO_COLOR = '\033[0m'
class TimeoutError(Exception):
pass
class Utils(object):
@staticmethod
def prepare_bpf_call(test):
return ('test={}; '.format(test.name) +
test.before + ' {}'.format(BPF_PATH) + test.run + ' ' + test.after)
@staticmethod
def __handler(signum, frame):
raise TimeoutError('TIMEOUT')
@staticmethod
def run_test(test):
signal.signal(signal.SIGALRM, Utils.__handler)
signal.alarm(test.timeout)
try:
bpf_call = Utils.prepare_bpf_call(test)
p = subprocess.Popen(
[bpf_call], shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
read_max_line = 4
total_lines_read = 0
line = '-'
output = ''
while (read_max_line > total_lines_read and line):
line = p.stdout.readline().decode('utf-8', 'ignore')
output += line + '\n'
total_lines_read += 1
result = re.search(test.expect, output)
except (TimeoutError):
print(test.name + ERROR_COLOR + ' ' + ' TIMEOUT ' + NO_COLOR)
return False
if result:
print(test.name + OK_COLOR + ' OK' + NO_COLOR)
return True
else:
print(test.name + ERROR_COLOR + ' ERROR' + NO_COLOR +
'\n\tExpected: ' + test.expect + '\n\tFound: ' + output)
return False
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment