Skip to content

Commit 1cd1eeb

Browse files
author
owen-jones-diffblue
authored
Merge pull request diffblue#511 from diffblue/owen-jones-diffblue/benchmarks-cron-job
Set up cron job for genuine benchmarks [SEC-471]
2 parents c4766c9 + 64595c1 commit 1cd1eeb

File tree

11 files changed

+330
-28
lines changed

11 files changed

+330
-28
lines changed

.travis.yml

Lines changed: 49 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ jobs:
77
include:
88

99
- &formatting-stage
10+
if: type != cron
1011
stage: Linter + Doxygen + non-debug Ubuntu/gcc-5 test
1112
env: NAME="clang-format"
1213
addons:
@@ -37,14 +38,16 @@ jobs:
3738
# LOCAL CHANGES: added cbmc/ prefix to both these scripts
3839

3940
- &linter-stage
41+
if: type != cron
4042
stage: Linter + Doxygen + non-debug Ubuntu/gcc-5 test
4143
env: NAME="CPP-LINT"
4244
install:
4345
script: cbmc/scripts/travis_lint.sh
4446
before_cache:
4547

4648
- &doxygen-stage
47-
- stage: Linter + Doxygen + non-debug Ubuntu/gcc-5 test
49+
if: type != cron
50+
stage: Linter + Doxygen + non-debug Ubuntu/gcc-5 test
4851
env: NAME="DOXYGEN-CHECK"
4952
addons:
5053
apt:
@@ -55,7 +58,8 @@ jobs:
5558
before_cache:
5659

5760
# Ubuntu Linux with glibc using g++-5
58-
- stage: Linter + Doxygen + non-debug Ubuntu/gcc-5 test
61+
- if: type != cron
62+
stage: Linter + Doxygen + non-debug Ubuntu/gcc-5 test
5963
os: linux
6064
sudo: false
6165
compiler: gcc
@@ -85,7 +89,8 @@ jobs:
8589
# LOCAL CHANGES: Added 'ant' to the OSX package list (needed by security-scanner regression tests)
8690

8791
# OS X using g++
88-
- stage: Test different OS/CXX/Flags
92+
- if: type != cron
93+
stage: Test different OS/CXX/Flags
8994
os: osx
9095
jdk: openjdk8
9196
osx_image: xcode8.3
@@ -105,7 +110,8 @@ jobs:
105110
- RUN_SECURITY_TESTS="true"
106111

107112
# OS X using clang++
108-
- stage: Test different OS/CXX/Flags
113+
- if: type != cron
114+
stage: Test different OS/CXX/Flags
109115
os: osx
110116
jdk: openjdk8
111117
osx_image: xcode8.3
@@ -124,7 +130,8 @@ jobs:
124130
- CCACHE_CPP2=yes
125131

126132
# Ubuntu Linux with glibc using g++-5, debug mode
127-
- stage: Test different OS/CXX/Flags
133+
- if: type != cron
134+
stage: Test different OS/CXX/Flags
128135
os: linux
129136
dist: trusty
130137
sudo: false
@@ -157,7 +164,8 @@ jobs:
157164
- TEST_MODELS_LIB="false"
158165

159166
# Ubuntu Linux with glibc using clang++-3.7
160-
- stage: Test different OS/CXX/Flags
167+
- if: type != cron
168+
stage: Test different OS/CXX/Flags
161169
os: linux
162170
dist: trusty
163171
sudo: false
@@ -193,7 +201,8 @@ jobs:
193201
- OS="ubuntu"
194202

195203
# Ubuntu Linux with glibc using clang++-3.7, debug mode
196-
- stage: Test different OS/CXX/Flags
204+
- if: type != cron
205+
stage: Test different OS/CXX/Flags
197206
os: linux
198207
sudo: false
199208
compiler: clang
@@ -224,6 +233,39 @@ jobs:
224233
- RUN_SECURITY_TESTS="true"
225234
- CCACHE_CPP2=yes
226235

236+
# LOCAL CHANGES: added cron-job stage
237+
238+
- &cron-job-stage
239+
if: type == cron
240+
stage: cron-job
241+
os: linux
242+
sudo: false
243+
compiler: gcc
244+
cache: ccache
245+
addons:
246+
apt:
247+
sources:
248+
- ubuntu-toolchain-r-test
249+
- deadsnakes
250+
packages:
251+
- libwww-perl
252+
- g++-5
253+
- libubsan0
254+
- python3-pip
255+
- libc6-dev-i386
256+
before_install:
257+
- mkdir bin ; ln -s /usr/bin/gcc-5 bin/gcc
258+
# Install pytest locally and adjust PATH so pip3 can find it
259+
- pip3 install -q pytest fasteners --user
260+
- export PATH=$HOME/.local/bin:$PATH
261+
env:
262+
- COMPILER="/usr/bin/g++-5"
263+
- BUILD_TYPE="Release"
264+
- RUN_CBMC_TESTS="false"
265+
- RUN_SECURITY_TESTS="true"
266+
- SECURITY_SCANNER_HOME=${TRAVIS_BUILD_DIR}/build
267+
script: (cd regression; python3 -m pytest -v -s --run-slow-only)
268+
227269

228270
allow_failures:
229271
- <<: *linter-stage

benchmarks/GENUINE/Alfresco.sh

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,14 @@ set -e
1111
SCRIPT_DIR="$( cd "$(dirname "$0")" ; pwd -P )"
1212
REPO_DIR=$SCRIPT_DIR/Alfresco
1313
DEPLOY_DIR=$REPO_DIR/__dist__
14+
FILES_DIR=$SCRIPT_DIR/Alfresco_files
15+
LIB_DIR=$SCRIPT_DIR/../LIBRARIES
1416
if [ -z "$OUTPUT_DIR" ]; then
1517
OUTPUT_DIR=$SECURITY_SCANNER_HOME/GENUINE
1618
fi
1719

20+
(cd $LIB_DIR && ./install_apache_tomcat.sh)
21+
1822
if [[ ! -d $REPO_DIR ]]; then
1923
# First switch to Java 7
2024
java_version=$(java -version 2>&1 | awk -F '"' '/version/ {print $2}')
@@ -40,10 +44,8 @@ if [[ ! -d $REPO_DIR ]]; then
4044
echo " where <name> is one of the options returned from the first command."
4145
exit 1
4246
fi
43-
echo "TEMPORARILY SWITCHING JAVA TO VERSION 7 LOCATED HERE:"
44-
echo " /usr/lib/jvm/java-7-openjdk-amd64/bin"
4547
PATH=/usr/lib/jvm/java-7-openjdk-amd64/bin:$PATH
46-
JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64/bin
48+
JAVA_HOME=/usr/lib/jvm/java-7-openjdk-amd64
4749
fi
4850

4951
# Clone the repository and check out a commit which has the issue.
@@ -55,8 +57,11 @@ if [[ ! -d $REPO_DIR ]]; then
5557
cd $REPO_DIR
5658
svn checkout -r 74720 https://svn.alfresco.com/repos/alfresco-open-mirror/alfresco/HEAD/root .
5759

60+
# Fix dependency version
61+
patch -p1 -f < $FILES_DIR/update_dependency.patch
62+
5863
# Build and install
59-
mvn install -DskipTests
64+
mvn install -DskipTests -Dhttps.protocols=TLSv1.2
6065

6166
# Deploy web apps
6267
mkdir -p $DEPLOY_DIR/webapps
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--- Alfresco/projects/repository/pom.xml 2018-07-19 17:39:07.513596311 +0100
2+
+++ Alfresco-fixed/projects/repository/pom.xml 2018-07-20 10:32:46.083159162 +0100
3+
@@ -579,7 +579,7 @@
4+
<dependency>
5+
<groupId>org.springframework.social</groupId>
6+
<artifactId>spring-social-facebook</artifactId>
7+
- <version>1.0.0.RC1</version>
8+
+ <version>1.0.0.RELEASE</version>
9+
</dependency>
10+
<dependency>
11+
<groupId>org.springframework.social</groupId>

benchmarks/GENUINE/Sakai.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ python3 $SCRIPT_DIR/../../driver/run.py \
4040
-R $OUTPUT_DIR/Sakai/results \
4141
-T $OUTPUT_DIR/Sakai/temp \
4242
--name sakai_assignment_tool \
43-
--use-models-library --use-apache-tomcat --use-spring-framework \
43+
--use-models-library \
4444
--timeout 10000000 --verbosity 9 --rebuild \
4545
--do-not-use-precise-access-paths \
4646
--entry-point org.sakaiproject.assignment.tool.AssignmentAction.doUpload_all

benchmarks/GENUINE/WebGoat.sh

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,19 +52,25 @@ fi
5252
# Run security-analyser on each lesson which works separately
5353
cd $SECURITY_SCANNER_HOME
5454

55+
rm -rf ${OUTPUT_DIR}/WebGoat
56+
mkdir -p ${OUTPUT_DIR}/WebGoat/results
57+
5558
for LESSON in $LESSONS_WHICH_WORK_SQL
5659
do
5760
python3 $SCRIPT_DIR/../../driver/run.py \
5861
-C $SCRIPT_DIR/WebGoatRulesSQL.json \
5962
-I $DEPLOY_DIR \
6063
-L $DEPLOY_DIR \
61-
-R $OUTPUT_DIR/WebGoat/results/$LESSON \
62-
-T $OUTPUT_DIR/WebGoat/temp \
64+
-R $OUTPUT_DIR/WebGoat/${LESSON}/results \
65+
-T $OUTPUT_DIR/WebGoat/${LESSON}/temp \
6366
--name WebGoat \
6467
--use-models-library \
6568
--timeout 10000000 --verbosity 9 --rebuild \
6669
--do-not-use-precise-access-paths \
6770
--entry-point Main.$LESSON
71+
72+
mv ${OUTPUT_DIR}/WebGoat/${LESSON}/results/* ${OUTPUT_DIR}/WebGoat/results
73+
rm -rf ${OUTPUT_DIR}/WebGoat/${LESSON}
6874
done
6975

7076
for LESSON in $LESSONS_WHICH_WORK_XSS
@@ -73,11 +79,14 @@ do
7379
-C $SCRIPT_DIR/WebGoatRulesXSS.json \
7480
-I $DEPLOY_DIR \
7581
-L $DEPLOY_DIR \
76-
-R $OUTPUT_DIR/WebGoat/results/$LESSON \
77-
-T $OUTPUT_DIR/WebGoat/temp \
82+
-R $OUTPUT_DIR/WebGoat/${LESSON}/results \
83+
-T $OUTPUT_DIR/WebGoat/${LESSON}/temp \
7884
--name WebGoat \
7985
--use-models-library \
8086
--timeout 10000000 --verbosity 9 --rebuild \
8187
--do-not-use-precise-access-paths \
8288
--entry-point Main.$LESSON
89+
90+
mv ${OUTPUT_DIR}/WebGoat/${LESSON}/results/* ${OUTPUT_DIR}/WebGoat/results
91+
rm -rf ${OUTPUT_DIR}/WebGoat/${LESSON}
8392
done

driver/run.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,8 +462,7 @@ def __main():
462462
if cmdline.name is None:
463463
cmdline.name = os.path.basename(cmdline.install_dir)
464464

465-
# If you're preparing a scan you implicitly want to rebuild everything.
466-
if cmdline.rebuild or cmdline.prepare_scan:
465+
if cmdline.rebuild:
467466
print("First performing cleanup.")
468467
print(" Deleting " + cmdline.temp_dir)
469468
if os.path.exists(cmdline.temp_dir):

regression/conftest.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,24 @@ class LoadStrategy(Enum):
1111
def load_strategy(request):
1212
"""Use fixture to parametrize tests"""
1313
return request.param
14+
15+
16+
def pytest_addoption(parser):
17+
parser.addoption(
18+
"--run-slow-only", action="store_true", default=False, help="run slow tests only"
19+
)
20+
21+
22+
def pytest_collection_modifyitems(config, items):
23+
if config.getoption("--run-slow-only"):
24+
# --run-slow-only given in cli: skip tests that are not marked slow
25+
skip_non_slow = pytest.mark.skip(reason="need to not have --run-slow-only option to run this test")
26+
for item in items:
27+
if "slow" not in item.keywords:
28+
item.add_marker(skip_non_slow)
29+
else:
30+
# --run-slow-only not given in cli: skip tests that are marked slow
31+
skip_slow = pytest.mark.skip(reason="need --run-slow-only option to run this test")
32+
for item in items:
33+
if "slow" in item.keywords:
34+
item.add_marker(skip_slow)

regression/executable_runner.py

Lines changed: 63 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,88 @@
1+
import os
2+
import signal
13
import subprocess
4+
import time
25

36

47
class ExecutableRunner:
58
"""Run an executable"""
69

7-
def __init__(self, cmd, timeout=600, encoding='utf-8'):
10+
def __init__(self, cmd, timeout=10, encoding='utf-8'):
811
"""Set the command to run, the timeout (optional) and the encoding (optional)
912
1013
cmd should be in the format excepted by subprocess.Popen, i.e. [executable_path, arg1, arg2, ...]
14+
timeout is in minutes
1115
"""
1216
self.cmd = cmd
1317
self.timeout = timeout
1418
self.encoding = encoding
1519

16-
def run(self, pipe_stderr_to_stdout=False):
20+
def run(self, pipe_stderr_to_stdout=False, env_dict=None, regular_log_messages=False):
1721
"""Run the executable and capture the output
1822
19-
If the process exceeds the timeout then we assert false so that the test fails.
23+
If the process exceeds the timeout then we raise a TimeoutError.
2024
2125
Return the tuple (output to stdout (string), output to stderr (string), exit code (int)).
2226
"""
2327
# We limit ourselves to the API available in python 3.3 to make life easier on Travis. There are API
2428
# improvements in python 3.5 and 3.6 which would make this code simpler.
29+
30+
# Allow the caller to pipe stderr to stdout
2531
stderr = subprocess.STDOUT if pipe_stderr_to_stdout else subprocess.PIPE
26-
proc = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=stderr)
27-
try:
28-
(stdout_data, stderr_data) = proc.communicate(timeout=self.timeout)
29-
except subprocess.TimeoutExpired:
30-
proc.kill()
31-
print('The executable ran for longer than {} seconds'.format(self.timeout))
32-
assert False
32+
33+
# Allow the caller to set environment variables in the subprocess
34+
env = None
35+
if env_dict:
36+
env = os.environ.copy()
37+
for key, value in env_dict.items():
38+
env[key] = value
39+
40+
# We must pass start_new_session=True so that we can kill the subprocess and all of its children using the
41+
# pid of the subprocess, without killing the process that pytest is running in
42+
proc = subprocess.Popen(self.cmd, stdout=subprocess.PIPE, stderr=stderr, env=env, start_new_session=True)
43+
if regular_log_messages:
44+
stdout_data, stderr_data = get_proc_output_with_regular_log_messages(proc, self.timeout)
45+
else:
46+
stdout_data, stderr_data = get_proc_output(proc, self.timeout)
47+
3348
return (stdout_data.decode(self.encoding) if stdout_data else None,
3449
stderr_data.decode(self.encoding) if stderr_data else None,
3550
proc.returncode)
51+
52+
53+
def get_proc_output(proc, timeout):
54+
try:
55+
stdout_data, stderr_data = proc.communicate(timeout=60*timeout)
56+
except subprocess.TimeoutExpired:
57+
kill_process_and_children(proc.pid)
58+
print('The executable ran for longer than {} minutes'.format(timeout))
59+
raise TimeoutError
60+
return stdout_data, stderr_data
61+
62+
63+
def get_proc_output_with_regular_log_messages(proc, timeout):
64+
stdout_data = None
65+
stderr_data = None
66+
num_minutes_run = 0
67+
print("")
68+
process_completed = False
69+
while not process_completed:
70+
try:
71+
stdout_data, stderr_data = proc.communicate(timeout=60)
72+
process_completed = True
73+
except subprocess.TimeoutExpired:
74+
print("pytest still running... ")
75+
num_minutes_run += 1
76+
if num_minutes_run >= timeout:
77+
kill_process_and_children(proc.pid)
78+
print('The executable ran for longer than {} minutes'.format(timeout))
79+
raise TimeoutError
80+
return stdout_data, stderr_data
81+
82+
83+
def kill_process_and_children(pid):
84+
# We can't just run `proc.kill()` because we have run a shell script which has run a python script,
85+
# which has run jbmc, and `proc.kill()` would only kill the shell script and not its children
86+
os.killpg(os.getpgid(pid), signal.SIGTERM)
87+
time.sleep(5)
88+
os.killpg(os.getpgid(pid), signal.SIGKILL)

regression/genuine_benchmarks/__init__.py

Whitespace-only changes.

0 commit comments

Comments
 (0)