Skip to content

Commit fdfabf3

Browse files
authored
Enable jenkins CI (#118)
- Enable CI - Committed test suite that was forgotten on dev machine.
1 parent 3a278e8 commit fdfabf3

13 files changed

+435
-12
lines changed

.coveragerc

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[run]
2+
source = isotp
3+
concurrency = thread

Dockerfile

+90
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
FROM ubuntu:20.04 as build-tests
2+
3+
ENV DEBIAN_FRONTEND=noninteractive
4+
5+
RUN apt-get update && apt-get install -y \
6+
git \
7+
wget \
8+
libssl-dev \
9+
build-essential \
10+
libffi-dev \
11+
libreadline-dev \
12+
zlib1g-dev \
13+
libsqlite3-dev \
14+
libssl-dev \
15+
iproute2 \
16+
&& rm -rf /var/lib/apt/lists/*
17+
18+
WORKDIR /tmp/
19+
20+
# ============================================
21+
ARG PYTHON_VERSION="3.11.1"
22+
ARG PYTHON_SRC="https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz"
23+
24+
RUN wget $PYTHON_SRC \
25+
&& tar -xvzf "Python-${PYTHON_VERSION}.tgz" \
26+
&& cd "Python-${PYTHON_VERSION}" \
27+
&& ./configure \
28+
&& make -j 4 \
29+
&& make install \
30+
&& cd .. \
31+
&& rm "Python-${PYTHON_VERSION}.tgz" \
32+
&& rm -rf "Python-${PYTHON_VERSION}"
33+
34+
35+
# ============================================
36+
ARG PYTHON_VERSION="3.10.9"
37+
ARG PYTHON_SRC="https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz"
38+
39+
RUN wget $PYTHON_SRC \
40+
&& tar -xvzf "Python-${PYTHON_VERSION}.tgz" \
41+
&& cd "Python-${PYTHON_VERSION}" \
42+
&& ./configure \
43+
&& make -j 4 \
44+
&& make install \
45+
&& cd .. \
46+
&& rm "Python-${PYTHON_VERSION}.tgz" \
47+
&& rm -rf "Python-${PYTHON_VERSION}"
48+
49+
# ============================================
50+
ARG PYTHON_VERSION="3.9.16"
51+
ARG PYTHON_SRC="https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz"
52+
53+
RUN wget $PYTHON_SRC \
54+
&& tar -xvzf "Python-${PYTHON_VERSION}.tgz" \
55+
&& cd "Python-${PYTHON_VERSION}" \
56+
&& ./configure \
57+
&& make -j 4 \
58+
&& make install \
59+
&& cd .. \
60+
&& rm "Python-${PYTHON_VERSION}.tgz" \
61+
&& rm -rf "Python-${PYTHON_VERSION}"
62+
63+
# ============================================
64+
ARG PYTHON_VERSION="3.8.16"
65+
ARG PYTHON_SRC="https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz"
66+
67+
RUN wget $PYTHON_SRC \
68+
&& tar -xvzf "Python-${PYTHON_VERSION}.tgz" \
69+
&& cd "Python-${PYTHON_VERSION}" \
70+
&& ./configure \
71+
&& make -j 4 \
72+
&& make install \
73+
&& cd .. \
74+
&& rm "Python-${PYTHON_VERSION}.tgz" \
75+
&& rm -rf "Python-${PYTHON_VERSION}"
76+
77+
# ============================================
78+
79+
ARG PYTHON_VERSION="3.7.17"
80+
ARG PYTHON_SRC="https://www.python.org/ftp/python/${PYTHON_VERSION}/Python-${PYTHON_VERSION}.tgz"
81+
82+
RUN wget $PYTHON_SRC \
83+
&& tar -xvzf "Python-${PYTHON_VERSION}.tgz" \
84+
&& cd "Python-${PYTHON_VERSION}" \
85+
&& ./configure \
86+
&& make -j 4 \
87+
&& make install \
88+
&& cd .. \
89+
&& rm "Python-${PYTHON_VERSION}.tgz" \
90+
&& rm -rf "Python-${PYTHON_VERSION}"

Jenkinsfile

+85
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
pipeline {
2+
agent {
3+
label 'docker'
4+
}
5+
stages {
6+
stage ('Docker') {
7+
agent {
8+
dockerfile {
9+
// Required to be root to create vcan interfaces
10+
args '-e HOME=/tmp -e BUILD_CONTEXT=ci --cap-add=NET_ADMIN -u 0:0'
11+
additionalBuildArgs '--target build-tests'
12+
reuseNode true
13+
}
14+
}
15+
stages {
16+
stage('Setup vcan'){
17+
steps {
18+
sh '''
19+
ip link add dev vcan0 type vcan || true
20+
ip link set up vcan0
21+
ip link add dev vcan1 type vcan || true
22+
ip link set up vcan1
23+
ip link add dev vcan2 type vcan || true
24+
ip link set up vcan2
25+
ip link add dev vcan3 type vcan || true
26+
ip link set up vcan3
27+
ip link add dev vcan4 type vcan || true
28+
ip link set up vcan4
29+
'''
30+
}
31+
}
32+
stage('Testing'){
33+
parallel{
34+
35+
stage ('Python 3.11') {
36+
steps {
37+
sh '''
38+
python3.11 -m venv venv-3.11
39+
VENV_DIR=venv-3.11 scripts/with-venv.sh scripts/check-python-version.sh 3.11
40+
VENV_DIR=venv-3.11 COVERAGE_SUFFIX=3.11 UNITTEST_VCAN=vcan0 scripts/with-venv.sh scripts/runtests.sh
41+
'''
42+
}
43+
}
44+
stage ('Python 3.10') {
45+
steps {
46+
sh '''
47+
python3.10 -m venv venv-3.10
48+
VENV_DIR=venv-3.10 scripts/with-venv.sh scripts/check-python-version.sh 3.10
49+
VENV_DIR=venv-3.10 COVERAGE_SUFFIX=3.10 UNITTEST_VCAN=vcan1 scripts/with-venv.sh scripts/runtests.sh
50+
'''
51+
}
52+
}
53+
stage ('Python 3.9') {
54+
steps {
55+
sh '''
56+
python3.9 -m venv venv-3.9
57+
VENV_DIR=venv-3.9 scripts/with-venv.sh scripts/check-python-version.sh 3.9
58+
VENV_DIR=venv-3.9 COVERAGE_SUFFIX=3.9 UNITTEST_VCAN=vcan2 scripts/with-venv.sh scripts/runtests.sh
59+
'''
60+
}
61+
}
62+
stage ('Python 3.8') {
63+
steps {
64+
sh '''
65+
python3.8 -m venv venv-3.8
66+
VENV_DIR=venv-3.8 scripts/with-venv.sh scripts/check-python-version.sh 3.8
67+
VENV_DIR=venv-3.8 COVERAGE_SUFFIX=3.8 UNITTEST_VCAN=vcan3 scripts/with-venv.sh scripts/runtests.sh
68+
'''
69+
}
70+
}
71+
stage ('Python 3.7') {
72+
steps {
73+
sh '''
74+
python3.7 -m venv venv-3.7
75+
VENV_DIR=venv-3.7 scripts/with-venv.sh scripts/check-python-version.sh 3.7
76+
VENV_DIR=venv-3.7 COVERAGE_SUFFIX=3.7 UNITTEST_VCAN=vcan4 scripts/with-venv.sh scripts/runtests.sh
77+
'''
78+
}
79+
}
80+
}
81+
}
82+
}
83+
}
84+
}
85+
}

doc/source/conf.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# -*- coding: utf-8 -*-
22
#
3-
# udsoncan documentation build configuration file, created by
3+
# isotp documentation build configuration file, created by
44
# sphinx-quickstart on Thu Apr 26 19:43:51 2018.
55
#
66
# This file is execfile()d with the current directory set to its

isotp/protocol.py

+4-3
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from collections.abc import Iterable
2828

2929

30-
from typing import Optional, Any, List, Callable, Dict, Tuple, Union, Generator
30+
from typing import Optional, Any, List, Callable, Dict, Tuple, Union, Generator, cast
3131

3232
try:
3333
import can
@@ -528,6 +528,7 @@ def __init__(self,
528528
gen, size = data
529529
self.generator = FiniteByteGenerator(gen, size)
530530
elif isinstance(data, Iterable):
531+
data = cast(Union[bytes, bytearray], data) # type:ignore
531532
self.generator = FiniteByteGenerator((x for x in data), len(data))
532533
else:
533534
raise ValueError("data must be an iterable element (bytes or bytearray) or a tuple of generator,size")
@@ -1684,11 +1685,11 @@ class BusOwner:
16841685

16851686
def python_can_tx_canbus_3plus(owner: BusOwner, msg: CanMessage) -> None:
16861687
owner.bus.send(can.Message(arbitration_id=msg.arbitration_id, data=msg.data,
1687-
is_extended_id=msg.is_extended_id, is_fd=msg.is_fd, bitrate_switch=msg.bitrate_switch)) # type:ignore
1688+
is_extended_id=msg.is_extended_id, is_fd=msg.is_fd, bitrate_switch=msg.bitrate_switch))
16881689

16891690

16901691
def python_can_tx_canbus_3minus(owner: BusOwner, msg: CanMessage) -> None:
1691-
owner.bus.send(can.Message(arbitration_id=msg.arbitration_id, data=msg.data,
1692+
owner.bus.send(can.Message(arbitration_id=msg.arbitration_id, data=msg.data, # type:ignore
16921693
extended_id=msg.is_extended_id, is_fd=msg.is_fd, bitrate_switch=msg.bitrate_switch)) # type:ignore
16931694

16941695

scripts/activate-venv.sh

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. >/dev/null 2>&1 && pwd -P )"
5+
PY_MODULE_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." >/dev/null 2>&1 && pwd -P )"
6+
7+
VENV_DIR="${VENV_DIR:-venv}"
8+
VENV_ROOT="${VENV_DIR:-$PROJECT_ROOT/$VENV_DIR}"
9+
10+
log() { echo -e "\x1B[92m[OK]\x1B[39m $@"; }
11+
12+
[ ! -d "$VENV_ROOT" ] \
13+
&& log "Missing venv. Creating..." \
14+
&& python3 -m venv "$VENV_ROOT"
15+
16+
source "$VENV_ROOT/bin/activate"
17+
18+
if ! pip3 show wheel 2>&1 >/dev/null; then
19+
log "Installing wheel..."
20+
pip3 install wheel
21+
log "Upgrading pip..."
22+
pip3 install --upgrade pip
23+
log "Upgrading setuptools..."
24+
pip3 install --upgrade setuptools
25+
fi
26+
27+
MODULE_FEATURE="[dev]"
28+
if ! [[ -z "${BUILD_CONTEXT+x}" ]]; then
29+
if [[ "$BUILD_CONTEXT" == "ci" ]]; then
30+
MODULE_FEATURE="[test]" # Will cause testing tools to be installed.
31+
fi
32+
fi
33+
34+
if ! diff "$PY_MODULE_ROOT/setup.py" "$VENV_ROOT/cache/setup.py" 2>&1 >/dev/null; then
35+
log "Install inside venv"
36+
pip3 install -e "${PY_MODULE_ROOT}${MODULE_FEATURE}"
37+
mkdir -p "$VENV_ROOT/cache/"
38+
cp "$PY_MODULE_ROOT/setup.py" "$VENV_ROOT/cache/setup.py"
39+
fi
40+
41+
set +e

scripts/check-python-version.sh

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
shopt -s nocasematch
5+
6+
if [ $# -eq 0 ]; then
7+
echo "Python version must be specified"
8+
exit 1
9+
fi
10+
11+
REQUIRED_VERSION=$1
12+
ACTUAL_PYTHON_VERSION=$(python3 --version)
13+
ACTUAL_PIP_VERSION=$(pip3 --version)
14+
15+
if [[ $ACTUAL_PYTHON_VERSION != *"python ${REQUIRED_VERSION}"* ]]; then
16+
echo "ERROR - Reported python3 version is ${ACTUAL_PYTHON_VERSION}. Expecting Python ${REQUIRED_VERSION}"
17+
exit 1
18+
fi
19+
20+
if [[ $ACTUAL_PIP_VERSION != *"python ${REQUIRED_VERSION}"* ]]; then
21+
echo "ERROR - Reported pip3 version is ${ACTUAL_PIP_VERSION}. Expecting pip for Python ${REQUIRED_VERSION}"
22+
exit 1
23+
fi
24+
25+
echo "Python version OK."
26+
echo " - ${ACTUAL_PYTHON_VERSION}"
27+
echo " - ${ACTUAL_PIP_VERSION}"
28+
exit 0

scripts/runtests.sh

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#!/bin/bash
2+
set -euo pipefail
3+
4+
COVERAGE_SUFFIX="${COVERAGE_SUFFIX:-dev}"
5+
HTML_COVDIR="htmlcov_${COVERAGE_SUFFIX}"
6+
COV_DATAFILE=".coverage_${COVERAGE_SUFFIX}"
7+
8+
if ! [[ -z "${BUILD_CONTEXT+x}" ]]; then
9+
if [[ "$BUILD_CONTEXT" == "ci" ]]; then
10+
if ! [[ -z "${NODE_NAME+x}" ]]; then
11+
echo "Running tests on agent: ${NODE_NAME}"
12+
fi
13+
fi
14+
fi
15+
16+
set -x
17+
18+
python3 -m coverage run --data-file ${COV_DATAFILE} -m unittest -v
19+
python3 -m mypy isotp --strict --no-warn-unused-ignore
20+
python3 -m coverage report --data-file ${COV_DATAFILE}
21+
python3 -m coverage html --data-file ${COV_DATAFILE} -d $HTML_COVDIR
22+

scripts/with-venv.sh

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
PROJECT_ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )"/.. >/dev/null 2>&1 && pwd -P )"
5+
source "$PROJECT_ROOT/scripts/activate-venv.sh"
6+
7+
set -e # activate-venv sets +e
8+
exec "$@"

setup.py

+4
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@
1111
name='can-isotp',
1212
packages=find_packages(where='.', exclude=['test', 'test.*'], include=['isotp', "isotp.*"]),
1313
version='2.0.4',
14+
extras_require={
15+
'test': ['mypy', 'coverage', 'python-can'],
16+
'dev': ['mypy', 'ipdb', 'autopep8', 'coverage', 'python-can']
17+
},
1418
description='Module enabling the IsoTP protocol defined by ISO-15765',
1519
long_description=long_description,
1620
author='Pier-Yves Lessard',

test/ThreadableTest.py

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import unittest
1+
import unittest
22
import queue
3-
import _thread as thread
43
import threading
54

6-
#Class borrowed from Python Socket test suite.
5+
# Class borrowed from Python Socket test suite.
6+
7+
78
class ThreadableTest(unittest.TestCase):
89
def __init__(self, *args, **kwargs):
910
unittest.TestCase.__init__(self, *args, **kwargs)
@@ -26,9 +27,10 @@ def _setUp(self):
2627
# Do some munging to start the client test.
2728
methodname = self.id()
2829
i = methodname.rfind('.')
29-
methodname = methodname[i+1:]
30+
methodname = methodname[i + 1:]
3031
test_method = getattr(self, '_' + methodname)
31-
self.client_thread = thread.start_new_thread(self.clientRun, (test_method,))
32+
self.client_thread = threading.Thread(target=self.clientRun, args=(test_method,))
33+
self.client_thread.start()
3234

3335
try:
3436
self.__setUp()
@@ -81,5 +83,5 @@ def _clientTearDown(self):
8183
self.clientTearDown()
8284
except BaseException as e:
8385
self.queue.put(e)
84-
finally:
85-
thread.exit()
86+
finally:
87+
raise SystemExit()

0 commit comments

Comments
 (0)