15 changed files with 325 additions and 3 deletions
@ -0,0 +1,4 @@ |
|||
**/__pycache__/ |
|||
build/ |
|||
dist/ |
|||
**/*.egg-info |
|||
@ -0,0 +1,25 @@ |
|||
version: "2" |
|||
|
|||
services: |
|||
monsun_postgres: |
|||
image: postgres |
|||
container_name: monsun_postgres |
|||
restart: always |
|||
volumes: |
|||
- ./db-data:/var/lib/postgresql/data |
|||
env_file: dev.env |
|||
|
|||
monsun_backend: |
|||
build: . |
|||
container_name: monsun_backd |
|||
restart: always |
|||
ports: |
|||
- 80:80 |
|||
volumes: |
|||
- ./config:/var/config/ |
|||
depends_on: |
|||
- monsun_postgres |
|||
environment: |
|||
POSTGRES_HOST: monsun_postgres |
|||
env_file: dev.env |
|||
command: ["bash", "./wait-for-it.sh", "monsun_postgres:5432", "-t", "60", "--", "./docker-entrypoint.sh"] |
|||
@ -0,0 +1,6 @@ |
|||
#!/usr/bin/env bash |
|||
source /opt/venv/bin/activate |
|||
flask db upgrade |
|||
|
|||
service nginx start |
|||
uwsgi --ini uwsgi.ini |
|||
@ -0,0 +1,3 @@ |
|||
docker build -t monsun_backend . |
|||
docker tag monsun_backend:latest registry.berthoud.dev/monsun_backend |
|||
docker push registry.berthoud.dev/monsun_backend:latest |
|||
@ -0,0 +1,45 @@ |
|||
# stage 1 |
|||
FROM python:3.8-slim-buster as backend-build |
|||
|
|||
VOLUME /app |
|||
WORKDIR /app |
|||
|
|||
RUN apt-get update \ |
|||
&& apt-get -y install python3-dev \ |
|||
&& apt-get -y install build-essential |
|||
|
|||
RUN python3 -m venv /opt/venv |
|||
|
|||
COPY . . |
|||
|
|||
RUN . /opt/venv/bin/activate \ |
|||
&& pip install --upgrade setuptools wheel \ |
|||
&& pip install -r requirements.txt \ |
|||
&& python setup.py sdist bdist_wheel \ |
|||
&& pip install monsun_backend --no-index --find-links file:///app/dist |
|||
|
|||
# stage 2 |
|||
FROM python:3.8-slim-buster |
|||
|
|||
RUN apt-get update \ |
|||
&& apt-get -y install nginx \ |
|||
&& apt-get -y install python3-dev \ |
|||
&& apt-get -y install build-essential \ |
|||
&& apt-get -qy install netcat |
|||
|
|||
RUN mkdir /var/config |
|||
VOLUME /var/config |
|||
|
|||
VOLUME /app |
|||
WORKDIR /app |
|||
|
|||
COPY docker-entrypoint.sh /app/docker-entrypoint.sh |
|||
COPY wait-for-it.sh /app/wait-for-it.sh |
|||
COPY wsgi.py /app/wsgi.py |
|||
COPY nginx.conf /etc/nginx |
|||
COPY uwsgi.ini /app/uwsgi.ini |
|||
COPY migrations /app/migrations |
|||
|
|||
COPY --from=backend-build /opt/venv /opt/venv |
|||
|
|||
CMD ["bash", "./docker-entrypoint.sh"] |
|||
@ -0,0 +1,47 @@ |
|||
user www-data; |
|||
worker_processes auto; |
|||
pid /run/nginx.pid; |
|||
|
|||
events { |
|||
worker_connections 1024; |
|||
use epoll; |
|||
multi_accept on; |
|||
} |
|||
|
|||
http { |
|||
access_log /dev/stdout; |
|||
error_log /dev/stdout; |
|||
|
|||
sendfile on; |
|||
tcp_nopush on; |
|||
tcp_nodelay on; |
|||
keepalive_timeout 65; |
|||
types_hash_max_size 2048; |
|||
|
|||
client_max_body_size 20M; |
|||
|
|||
include /etc/nginx/mime.types; |
|||
default_type application/octet-stream; |
|||
|
|||
index index.html index.htm; |
|||
|
|||
server { |
|||
listen 80 default_server; |
|||
listen [::]:80 default_server; |
|||
server_name localhost; |
|||
root /var/www/html; |
|||
|
|||
location / { |
|||
include uwsgi_params; |
|||
uwsgi_pass unix:/tmp/uwsgi.socket; |
|||
uwsgi_read_timeout 1h; |
|||
uwsgi_send_timeout 1h; |
|||
proxy_send_timeout 1h; |
|||
proxy_read_timeout 1h; |
|||
|
|||
proxy_buffer_size 128k; |
|||
proxy_buffers 4 256k; |
|||
proxy_busy_buffers_size 256k; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,74 @@ |
|||
import logging |
|||
import os |
|||
|
|||
import pytest |
|||
import requests |
|||
from flask_api import status |
|||
|
|||
BASE_URL = os.environ.get("TEST_BASE_URL", "http://localhost") |
|||
LOGIN_URI = BASE_URL + "/login" |
|||
LOGOUT_URI = BASE_URL + "/logout" |
|||
ADMIN_URI = BASE_URL + "/admin" |
|||
|
|||
PASSWORD = os.environ.get("MONSUN_PASSWORD", "password") |
|||
|
|||
|
|||
@pytest.fixture(autouse=True) |
|||
def log_variables(): |
|||
logger = logging.getLogger("system tests") |
|||
logger.info(f"BASE_URL: {BASE_URL}") |
|||
|
|||
|
|||
@pytest.fixture() |
|||
def session() -> requests.Session: |
|||
session = requests.Session() |
|||
response_login = session.post( |
|||
url=LOGIN_URI, |
|||
data={"email": "andreasberthoud@gmail.com", "password": PASSWORD}, |
|||
) |
|||
assert response_login.status_code == status.HTTP_200_OK |
|||
return session |
|||
|
|||
|
|||
def test_login_as_admin_and_accessing_admin_endpoint(): |
|||
session_admin_ = requests.Session() |
|||
response_login = session_admin_.post( |
|||
url=LOGIN_URI, |
|||
data={"email": "andreasberthoud@gmail.com", "password": PASSWORD}, |
|||
) |
|||
assert response_login.status_code == status.HTTP_200_OK |
|||
|
|||
response_admin_logged_in = session_admin_.get( |
|||
url=ADMIN_URI, |
|||
) |
|||
assert response_admin_logged_in.status_code == status.HTTP_200_OK |
|||
|
|||
response_logout = session_admin_.delete( |
|||
url=LOGOUT_URI, |
|||
) |
|||
assert response_logout.status_code == status.HTTP_200_OK |
|||
|
|||
response_admin_logged_out = session_admin_.get( |
|||
url=ADMIN_URI, |
|||
) |
|||
assert response_admin_logged_out.status_code == status.HTTP_403_FORBIDDEN |
|||
|
|||
|
|||
def test_toggle_client_led_then_status_is_ok(session): |
|||
response = session.post( |
|||
url=BASE_URL + "/client/command?cmd=led&id=red&command=toggle", |
|||
) |
|||
assert response.status_code == status.HTTP_200_OK |
|||
|
|||
|
|||
def test_pair_with_server_then_status_is_ok(session): |
|||
response = session.post(url=BASE_URL + "/client/command?cmd=gp&command_id=1") |
|||
assert response.status_code == status.HTTP_200_OK |
|||
|
|||
|
|||
def test_toggle_server_led_then_status_is_ok(session): |
|||
"""Requires a connected GATT server""" |
|||
response = session.post( |
|||
url=BASE_URL + "/client/command?cmd=led&id=red&command=toggle&target=server", |
|||
) |
|||
assert response.status_code == status.HTTP_200_OK |
|||
@ -0,0 +1,12 @@ |
|||
version: "2" |
|||
|
|||
services: |
|||
tests_monsun_postgres-test: |
|||
image: postgres |
|||
environment: |
|||
POSTGRES_PASSWORD: pass |
|||
POSTGRES_USER: usr |
|||
POSTGRES_DB: sqlalchemy |
|||
POSTGRES_HOST: postgres |
|||
ports: |
|||
- 5432:5432 |
|||
@ -1 +1,3 @@ |
|||
pytest |
|||
pytest-env |
|||
requests |
|||
|
|||
@ -0,0 +1,12 @@ |
|||
[uwsgi] |
|||
wsgi-file = wsgi.py |
|||
uid = www-data |
|||
gid = www-data |
|||
master = true |
|||
processes = 5 |
|||
|
|||
socket = /tmp/uwsgi.socket |
|||
chmod-sock = 664 |
|||
vacuum = true |
|||
|
|||
die-on-term = true |
|||
@ -0,0 +1,79 @@ |
|||
#!/bin/sh |
|||
# https://github.com/vishnubob/wait-for-it |
|||
TIMEOUT=15 |
|||
QUIET=0 |
|||
|
|||
echoerr() { |
|||
if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi |
|||
} |
|||
|
|||
usage() { |
|||
exitcode="$1" |
|||
cat << USAGE >&2 |
|||
Usage: |
|||
$cmdname host:port [-t timeout] [-- command args] |
|||
-q | --quiet Do not output any status messages |
|||
-t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout |
|||
-- COMMAND ARGS Execute command with args after the test finishes |
|||
USAGE |
|||
exit "$exitcode" |
|||
} |
|||
|
|||
wait_for() { |
|||
for i in `seq $TIMEOUT` ; do |
|||
nc -z "$HOST" "$PORT" > /dev/null 2>&1 |
|||
|
|||
result=$? |
|||
if [ $result -eq 0 ] ; then |
|||
if [ $# -gt 0 ] ; then |
|||
exec "$@" |
|||
fi |
|||
exit 0 |
|||
fi |
|||
sleep 1 |
|||
done |
|||
echo "Operation timed out" >&2 |
|||
exit 1 |
|||
} |
|||
|
|||
while [ $# -gt 0 ] |
|||
do |
|||
case "$1" in |
|||
*:* ) |
|||
HOST=$(printf "%s\n" "$1"| cut -d : -f 1) |
|||
PORT=$(printf "%s\n" "$1"| cut -d : -f 2) |
|||
shift 1 |
|||
;; |
|||
-q | --quiet) |
|||
QUIET=1 |
|||
shift 1 |
|||
;; |
|||
-t) |
|||
TIMEOUT="$2" |
|||
if [ "$TIMEOUT" = "" ]; then break; fi |
|||
shift 2 |
|||
;; |
|||
--timeout=*) |
|||
TIMEOUT="${1#*=}" |
|||
shift 1 |
|||
;; |
|||
--) |
|||
shift |
|||
break |
|||
;; |
|||
--help) |
|||
usage 0 |
|||
;; |
|||
*) |
|||
echoerr "Unknown argument: $1" |
|||
usage 1 |
|||
;; |
|||
esac |
|||
done |
|||
|
|||
if [ "$HOST" = "" -o "$PORT" = "" ]; then |
|||
echoerr "Error: you need to provide a host and port to test." |
|||
usage 2 |
|||
fi |
|||
|
|||
wait_for "$@" |
|||
Loading…
Reference in new issue