diff --git a/.coveragerc b/.coveragerc
new file mode 100644
index 0000000000000000000000000000000000000000..c910f0d6641a7393160699580449e043337fbaf4
--- /dev/null
+++ b/.coveragerc
@@ -0,0 +1,2 @@
+[run]
+include = librarytrader/*
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..f2c9a0a7a1b675bb21fbb291e80c048fc99c636e
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,41 @@
+# This file is a template, and might need editing before it works on your project.
+# Official language image. Look for the different tagged releases at:
+# https://hub.docker.com/r/library/python/tags/
+image: python:latest
+
+# Change pip's cache directory to be inside the project directory since we can
+# only cache local items.
+variables:
+  PIP_CACHE_DIR: "$CI_PROJECT_DIR/.cache"
+
+# Pip's cache doesn't store the python packages
+# https://pip.pypa.io/en/stable/reference/pip_install/#caching
+#
+# If you want to also cache the installed packages, you have to install
+# them in a virtualenv and cache it as well.
+cache:
+  paths:
+    - .cache/pip
+    - venv/
+
+before_script:
+  - python -V               # Print out python version for debugging
+  - pip install virtualenv
+  - virtualenv venv
+  - source venv/bin/activate
+
+test:
+  stage: test
+  script:
+    - pip install .
+    - pip install coverage coverage-badge
+    # Workaround for buggy pip installation of capstone
+    - PYVER=$(python --version 2>&1 | sed -e 's/\ //g' -e 's/P/p/g' | cut -c1-9); WRONGFILE="./venv/lib/$PYVER/site-packages/$PWD/venv/lib/$PYVER/site-packages/capstone/libcapstone.so"; TARGET="./venv/lib/$PYVER/site-packages/capstone"; if [ -f "$WRONGFILE" ]; then cp "$WRONGFILE" "$TARGET"; fi
+    - coverage run --concurrency=multiprocessing test/run_tests.py
+    - coverage combine
+    - coverage html
+    - coverage-badge -o htmlcov/coverage.svg
+    - coverage report
+  artifacts:
+    paths:
+      - htmlcov