Skip to content

Commit

Permalink
Run BCC test suite with github actions
Browse files Browse the repository at this point in the history
With this commit, pushes to branches can trigger tests directly on
Github Actions.

Here it will be able to test against kernel 4.14 and 5.0.0, which correspond
to the latest Ubuntu LTS kernel releases.

Tests are run for both Debug and Release modes.

Tests run inside docker, in an ubuntu 19.04 container base.

For the github workflow:

- The test_libbcc suite is run first, to potentially fail fast on these faster
unit tests.
- The Python test suite is run

Some of these tests are allowed to fail, but the failure is still reported:

- In catch2 tests, using the [!mayfail] tag, where this will be displayed in
the test summary
- In Python unittests, using the `@mayFail("Reason")` decorator, which is
introduce for consistency with catch2. These will report the reason for the
failure, and log this to an artifact of the test.
  • Loading branch information
dalehamel authored and yonghong-song committed Jan 29, 2020
1 parent 83b67c2 commit a47c44f
Show file tree
Hide file tree
Showing 16 changed files with 253 additions and 20 deletions.
94 changes: 94 additions & 0 deletions .github/workflows/bcc-test.yml
@@ -0,0 +1,94 @@
name: BCC Build and tests

on: push

jobs:
test_bcc:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-16.04, ubuntu-18.04] # 16.04.4 release has 4.15 kernel
# 18.04.3 release has 5.0.0 kernel
env:
- TYPE: Debug
PYTHON_TEST_LOGFILE: critical.log
- TYPE: Release
PYTHON_TEST_LOGFILE: critical.log
steps:
- uses: actions/checkout@v2
- name: System info
run: |
uname -a
ip addr
- name: Build docker container with all deps
run: |
docker build -t bcc-docker -f Dockerfile.tests .
- name: Run bcc build
env: ${{ matrix.env }}
run: |
/bin/bash -c \
"docker run --privileged \
--pid=host \
-v $(pwd):/bcc \
-v /sys/kernel/debug:/sys/kernel/debug:rw \
-v /lib/modules:/lib/modules:ro \
-v /usr/src:/usr/src:ro \
-v /usr/include/linux:/usr/include/linux:ro \
bcc-docker \
/bin/bash -c \
'mkdir -p /bcc/build && cd /bcc/build && \
cmake -DCMAKE_BUILD_TYPE=${TYPE} .. && make -j9'"
- name: Run bcc's cc tests
env: ${{ matrix.env }}
# tests are wrapped with `script` as a hack to get a TTY as github actions doesn't provide this
# see https://github.com/actions/runner/issues/241
run: |
script -e -c /bin/bash -c \
"docker run -ti \
--privileged \
--network=host \
--pid=host \
-v $(pwd):/bcc \
-v /sys/kernel/debug:/sys/kernel/debug:rw \
-v /lib/modules:/lib/modules:ro \
-v /usr/src:/usr/src:ro \
-e CTEST_OUTPUT_ON_FAILURE=1 \
bcc-docker \
/bin/bash -c \
'/bcc/build/tests/wrapper.sh \
c_test_all sudo /bcc/build/tests/cc/test_libbcc'"
- name: Run all tests
env: ${{ matrix.env }}
run: |
script -e -c /bin/bash -c \
"docker run -ti \
--privileged \
--network=host \
--pid=host \
-v $(pwd):/bcc \
-v /sys/kernel/debug:/sys/kernel/debug:rw \
-v /lib/modules:/lib/modules:ro \
-v /usr/src:/usr/src:ro \
-e CTEST_OUTPUT_ON_FAILURE=1 \
bcc-docker \
/bin/bash -c \
'cd /bcc/build && \
make test PYTHON_TEST_LOGFILE=$PYTHON_TEST_LOGFILE ARGS=-V'"
- name: Check critical tests
env: ${{ matrix.env }}
run: |
critical_count=$(grep @mayFail tests/python/critical.log | wc -l)
echo "There were $critical_count critical tests skipped with @mayFail:"
grep -A2 @mayFail tests/python/critical.log
- uses: actions/upload-artifact@v1
with:
name: critical-tests-${{ matrix.env['TYPE'] }}-${{ matrix.os }}
path: tests/python/critical.log

# To debug weird issues, you can add this step to be able to SSH to the test environment
# https://github.com/marketplace/actions/debugging-with-tmate
# - name: Setup tmate session
# uses: mxschmitt/action-tmate@v1
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -9,5 +9,6 @@
/build/
cmake-build-debug
debian/**/*.log
*critical.log
obj-x86_64-linux-gnu
examples/cgroupid/cgroupid
69 changes: 69 additions & 0 deletions Dockerfile.tests
@@ -0,0 +1,69 @@
# Using ubuntu 19.04 for newer `unshare` command used in tests
FROM ubuntu:19.04

ARG LLVM_VERSION="8"
ENV LLVM_VERSION=$LLVM_VERSION

RUN apt-get update && apt-get install -y curl gnupg &&\
llvmRepository="\n\
deb http://apt.llvm.org/disco/ llvm-toolchain-disco main\n\
deb-src http://apt.llvm.org/disco/ llvm-toolchain-disco main\n\
deb http://apt.llvm.org/disco/ llvm-toolchain-disco-${LLVM_VERSION} main\n\
deb-src http://apt.llvm.org/disco/ llvm-toolchain-disco-${LLVM_VERSION} main\n" &&\
echo $llvmRepository >> /etc/apt/sources.list && \
curl -L https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -

RUN apt-get update && apt-get install -y \
bison \
binutils-dev \
cmake \
flex \
g++ \
git \
kmod \
wget \
libelf-dev \
zlib1g-dev \
libiberty-dev \
libbfd-dev \
libedit-dev \
clang-${LLVM_VERSION} \
libclang-${LLVM_VERSION}-dev \
libclang-common-${LLVM_VERSION}-dev \
libclang1-${LLVM_VERSION} \
llvm-${LLVM_VERSION} \
llvm-${LLVM_VERSION}-dev \
llvm-${LLVM_VERSION}-runtime \
libllvm${LLVM_VERSION} \
systemtap-sdt-dev \
sudo \
iproute2 \
python3 \
python3-pip \
python-pip \
ethtool \
arping \
netperf \
iperf \
iputils-ping \
bridge-utils \
libtinfo5 \
libtinfo-dev

RUN pip3 install pyroute2 netaddr
RUN pip install pyroute2 netaddr

# FIXME this is faster than building from source, but it seems there is a bug
# in probing libruby.so rather than ruby binary
#RUN apt-get update -qq && \
# apt-get install -y software-properties-common && \
# apt-add-repository ppa:brightbox/ruby-ng && \
# apt-get update -qq && apt-get install -y ruby2.6 ruby2.6-dev

RUN wget -O ruby-install-0.7.0.tar.gz \
https://github.com/postmodern/ruby-install/archive/v0.7.0.tar.gz && \
tar -xzvf ruby-install-0.7.0.tar.gz && \
cd ruby-install-0.7.0/ && \
make install

RUN ruby-install --system ruby 2.6.0 -- --enable-dtrace
27 changes: 16 additions & 11 deletions examples/networking/simulation.py
Expand Up @@ -40,7 +40,10 @@ def _ns_add_ifc(self, name, ns_ifc, ifc_base_name=None, in_ifc=None,
"net.ipv6.conf.default.disable_ipv6=1"]
nsp = NSPopen(ns_ipdb.nl.netns, cmd1)
nsp.wait(); nsp.release()
ns_ipdb.interfaces.lo.up().commit()
try:
ns_ipdb.interfaces.lo.up().commit()
except pyroute2.ipdb.exceptions.CommitException:
print("Warning, commit for lo failed, operstate may be unknown")
if in_ifc:
in_ifname = in_ifc.ifname
with in_ifc as v:
Expand All @@ -65,17 +68,19 @@ def _ns_add_ifc(self, name, ns_ifc, ifc_base_name=None, in_ifc=None,
raise

if out_ifc: out_ifc.up().commit()

# this is a workaround for fc31 and possible other disto's.
# when interface 'lo' is already up, do another 'up().commit()'
# has issues in fc31.
# the workaround may become permanent if we upgrade pyroute2
# in all machines.
if 'state' in ns_ipdb.interfaces.lo.keys():
if ns_ipdb.interfaces.lo['state'] != 'up':
try:
# this is a workaround for fc31 and possible other disto's.
# when interface 'lo' is already up, do another 'up().commit()'
# has issues in fc31.
# the workaround may become permanent if we upgrade pyroute2
# in all machines.
if 'state' in ns_ipdb.interfaces.lo.keys():
if ns_ipdb.interfaces.lo['state'] != 'up':
ns_ipdb.interfaces.lo.up().commit()
else:
ns_ipdb.interfaces.lo.up().commit()
else:
ns_ipdb.interfaces.lo.up().commit()
except pyroute2.ipdb.exceptions.CommitException:
print("Warning, commit for lo failed, operstate may be unknown")
ns_ipdb.initdb()
in_ifc = ns_ipdb.interfaces[in_ifname]
with in_ifc as v:
Expand Down
4 changes: 2 additions & 2 deletions tests/cc/test_c_api.cc
Expand Up @@ -485,7 +485,7 @@ struct mod_search {
uint64_t file_offset;
};

TEST_CASE("searching for modules in /proc/[pid]/maps", "[c_api]") {
TEST_CASE("searching for modules in /proc/[pid]/maps", "[c_api][!mayfail]") {
FILE *dummy_maps = fopen("dummy_proc_map.txt", "r");
REQUIRE(dummy_maps != NULL);

Expand Down Expand Up @@ -580,7 +580,7 @@ TEST_CASE("searching for modules in /proc/[pid]/maps", "[c_api]") {
fclose(dummy_maps);
}

TEST_CASE("resolve global addr in libc in this process", "[c_api]") {
TEST_CASE("resolve global addr in libc in this process", "[c_api][!mayfail]") {
int pid = getpid();
char *sopath = bcc_procutils_which_so("c", pid);
uint64_t local_addr = 0x15;
Expand Down
9 changes: 6 additions & 3 deletions tests/cc/test_usdt_probes.cc
Expand Up @@ -199,7 +199,9 @@ static int unshared_child_pid(const int ppid) {
return child_pid;
}

TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt]") {
// FIXME This seems like a legitimate bug with probing ruby where the
// ruby symbols are in libruby.so?
TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt][!mayfail]") {
size_t mri_probe_count = 0;

SECTION("without a running Ruby process") {
Expand Down Expand Up @@ -338,8 +340,9 @@ TEST_CASE("test probing running Ruby process in namespaces",

SECTION("in separate mount namespace and separate PID namespace") {
static char _unshare[] = "unshare";
const char *const argv[7] = {_unshare, "--fork", "--mount", "--pid",
"--mount-proc", "ruby", NULL};
const char *const argv[8] = {_unshare, "--fork", "--kill-child",
"--mount", "--pid", "--mount-proc",
"ruby", NULL};

ChildProcess unshare(argv[0], (char **const)argv);
if (!unshare.spawned())
Expand Down
3 changes: 2 additions & 1 deletion tests/python/test_brb2.py
Expand Up @@ -57,7 +57,7 @@
from ctypes import c_uint
from bcc import BPF
from pyroute2 import IPRoute, NetNS, IPDB, NSPopen
from utils import NSPopenWithCheck
from utils import NSPopenWithCheck, mayFail
import sys
from time import sleep
from unittest import main, TestCase
Expand Down Expand Up @@ -136,6 +136,7 @@ def config_maps(self):
self.attach_filter(self.veth_br1_2_pem, self.pem_fn.fd, self.pem_fn.name)
self.attach_filter(self.veth_br2_2_pem, self.pem_fn.fd, self.pem_fn.name)

@mayFail("This fails on github actions environment, and needs to be fixed")
def test_brb2(self):
try:
b = BPF(src_file=arg1, debug=0)
Expand Down
3 changes: 3 additions & 0 deletions tests/python/test_debuginfo.py
Expand Up @@ -6,6 +6,7 @@
import subprocess
from bcc import SymbolCache, BPF
from unittest import main, TestCase
from utils import mayFail

class TestKSyms(TestCase):
def grab_sym(self):
Expand Down Expand Up @@ -100,6 +101,7 @@ def tearDown(self):
def test_resolve_addr(self):
self.resolve_addr()

@mayFail("This fails on github actions environment, and needs to be fixed")
def test_resolve_name(self):
self.resolve_name()

Expand Down Expand Up @@ -130,6 +132,7 @@ def tearDown(self):
def test_resolve_name(self):
self.resolve_addr()

@mayFail("This fails on github actions environment, and needs to be fixed")
def test_resolve_addr(self):
self.resolve_name()

Expand Down
2 changes: 2 additions & 0 deletions tests/python/test_stackid.py
Expand Up @@ -6,6 +6,7 @@
import distutils.version
import os
import unittest
from utils import mayFail
import subprocess

def kernel_version_ge(major, minor):
Expand All @@ -22,6 +23,7 @@ def kernel_version_ge(major, minor):

@unittest.skipUnless(kernel_version_ge(4,6), "requires kernel >= 4.6")
class TestStackid(unittest.TestCase):
@mayFail("This fails on github actions environment, and needs to be fixed")
def test_simple(self):
b = bcc.BPF(text="""
#include <uapi/linux/ptrace.h>
Expand Down
4 changes: 4 additions & 0 deletions tests/python/test_tools_smoke.py
Expand Up @@ -7,6 +7,7 @@
import os
import re
from unittest import main, skipUnless, TestCase
from utils import mayFail

TOOLS_DIR = "../../tools/"

Expand Down Expand Up @@ -65,6 +66,7 @@ def setUp(self):
def tearDown(self):
pass

@mayFail("This fails on github actions environment, and needs to be fixed")
def test_argdist(self):
self.run_with_duration("argdist.py -v -C 'p::do_sys_open()' -n 1 -i 1")

Expand Down Expand Up @@ -295,6 +297,7 @@ def test_solisten(self):
self.run_with_int("solisten.py")

@skipUnless(kernel_version_ge(4,4), "requires kernel >= 4.4")
@mayFail("This fails on github actions environment, and needs to be fixed")
def test_sslsniff(self):
self.run_with_int("sslsniff.py")

Expand Down Expand Up @@ -335,6 +338,7 @@ def test_tcpretrans(self):
self.run_with_int("tcpretrans.py")

@skipUnless(kernel_version_ge(4, 7), "requires kernel >= 4.7")
@mayFail("This fails on github actions environment, and needs to be fixed")
def test_tcpdrop(self):
self.run_with_int("tcpdrop.py")

Expand Down
2 changes: 2 additions & 0 deletions tests/python/test_trace3.py
Expand Up @@ -7,6 +7,7 @@
from time import sleep
import sys
from unittest import main, TestCase
from utils import mayFail

arg1 = sys.argv.pop(1)
arg2 = ""
Expand All @@ -15,6 +16,7 @@


class TestBlkRequest(TestCase):
@mayFail("This fails on github actions environment, and needs to be fixed")
def setUp(self):
b = BPF(arg1, arg2, debug=0)
self.latency = b.get_table("latency", c_uint, c_ulong)
Expand Down
2 changes: 2 additions & 0 deletions tests/python/test_usdt.py
Expand Up @@ -8,6 +8,7 @@
from __future__ import print_function
from bcc import BPF, USDT
from unittest import main, TestCase
from utils import mayFail
from subprocess import Popen, PIPE
from tempfile import NamedTemporaryFile
import ctypes as ct
Expand Down Expand Up @@ -139,6 +140,7 @@ def setUp(self):
self.assertEqual(comp.wait(), 0)
self.app = Popen([self.ftemp.name])

@mayFail("This fails on github actions environment, and needs to be fixed")
def test_attach1(self):
# enable USDT probe from given PID and verifier generated BPF programs
u = USDT(pid=int(self.app.pid))
Expand Down
2 changes: 2 additions & 0 deletions tests/python/test_usdt2.py
Expand Up @@ -8,6 +8,7 @@
from __future__ import print_function
from bcc import BPF, USDT
from unittest import main, TestCase
from utils import mayFail
from subprocess import Popen, PIPE
from tempfile import NamedTemporaryFile
import ctypes as ct
Expand Down Expand Up @@ -94,6 +95,7 @@ def setUp(self):
self.app2 = Popen([self.ftemp.name, "11"])
self.app3 = Popen([self.ftemp.name, "21"])

@mayFail("This fails on github actions environment, and needs to be fixed")
def test_attach1(self):
# Enable USDT probe from given PID and verifier generated BPF programs.
u = USDT(pid=int(self.app.pid))
Expand Down

0 comments on commit a47c44f

Please sign in to comment.