2
0
mirror of https://github.com/frappe/frappe_docker.git synced 2024-11-09 23:00:56 +00:00

Update tests

This commit is contained in:
Lev Vereshchagin 2021-12-13 19:37:03 +03:00
parent 3251b093a4
commit 666fa9a61f
10 changed files with 405 additions and 396 deletions

View File

@ -0,0 +1,23 @@
version: "3.9"
services:
backend:
image: localhost:5000/frappe/erpnext-backend:latest
frontend:
image: localhost:5000/frappe/erpnext-frontend:latest
websocket:
image: localhost:5000/frappe/socketio:latest
queue-short:
image: localhost:5000/frappe/erpnext-backend:latest
queue-default:
image: localhost:5000/frappe/erpnext-backend:latest
queue-long:
image: localhost:5000/frappe/erpnext-backend:latest
scheduler:
image: localhost:5000/frappe/erpnext-backend:latest

23
tests/compose.ci.yml Normal file
View File

@ -0,0 +1,23 @@
version: "3.9"
services:
backend:
image: localhost:5000/frappe/backend:latest
frontend:
image: localhost:5000/frappe/frontend:latest
websocket:
image: localhost:5000/frappe/socketio:latest
queue-short:
image: localhost:5000/frappe/backend:latest
queue-default:
image: localhost:5000/frappe/backend:latest
queue-long:
image: localhost:5000/frappe/backend:latest
scheduler:
image: localhost:5000/frappe/backend:latest

View File

@ -1,26 +0,0 @@
#!/bin/bash
print_group() {
echo ::endgroup::
echo "::group::$*"
}
ping_site() {
print_group "Ping site $SITE_NAME"
echo Ping version
ping_res=$(curl -sS "http://$SITE_NAME/api/method/version")
echo "$ping_res"
if [[ -z $(echo "$ping_res" | grep "message" || echo "") ]]; then
echo "Ping failed"
exit 1
fi
echo Check index
index_res=$(curl -sS "http://$SITE_NAME")
if [[ -n $(echo "$index_res" | grep "Internal Server Error" || echo "") ]]; then
echo "Index check failed"
echo "$index_res"
exit 1
fi
}

View File

@ -1,283 +0,0 @@
#!/bin/bash
set -e
source tests/functions.sh
project_name=frappe_bench_00
docker_compose_with_args() {
# shellcheck disable=SC2068
docker-compose \
-p $project_name \
-f installation/docker-compose-common.yml \
-f installation/docker-compose-frappe.yml \
-f installation/frappe-publish.yml \
$@
}
check_migration_complete() {
print_group Check migration
container_id=$(docker_compose_with_args ps -q frappe-python)
cmd="docker logs ${container_id} 2>&1 | grep 'Starting gunicorn' || echo ''"
worker_log=$(eval "$cmd")
INCREMENT=0
while [[ ${worker_log} != *"Starting gunicorn"* && ${INCREMENT} -lt 120 ]]; do
sleep 3
((INCREMENT = INCREMENT + 1))
echo "Wait for migration to complete..."
worker_log=$(eval "$cmd")
if [[ ${worker_log} != *"Starting gunicorn"* && ${INCREMENT} -eq 120 ]]; then
echo Migration timeout
docker logs "${container_id}"
exit 1
fi
done
echo Migration Log
docker logs "${container_id}"
}
check_health() {
print_group Loop health check
docker run --name frappe_doctor \
-v "${project_name}_sites-vol:/home/frappe/frappe-bench/sites" \
--network "${project_name}_default" \
frappe/frappe-worker:edge doctor || true
cmd='docker logs frappe_doctor | grep "Health check successful" || echo ""'
doctor_log=$(eval "$cmd")
INCREMENT=0
while [[ -z "${doctor_log}" && ${INCREMENT} -lt 60 ]]; do
sleep 1
((INCREMENT = INCREMENT + 1))
container=$(docker start frappe_doctor)
echo "Restarting ${container}..."
doctor_log=$(eval "$cmd")
if [[ ${INCREMENT} -eq 60 ]]; then
docker logs "${container}"
exit 1
fi
done
}
# Initial group
echo ::group::Setup .env
cp env-example .env
sed -i -e "s/edge/v13/g" .env
cat .env
# shellcheck disable=SC2046
export $(cat .env)
print_group Start services
echo Start main services
docker_compose_with_args up -d --quiet-pull
echo Start postgres
docker pull postgres:11.8 -q
docker run \
--name postgresql \
-d \
-e POSTGRES_PASSWORD=admin \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
postgres:11.8
check_health
print_group "Create new site "
SITE_NAME=test.localhost
docker run \
--rm \
-e SITE_NAME=$SITE_NAME \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:v13 new
ping_site
print_group "Update .env (v13 -> edge)"
sed -i -e "s/v13/edge/g" .env
cat .env
# shellcheck disable=SC2046
export $(cat .env)
print_group Restart containers
docker_compose_with_args stop
docker_compose_with_args up -d
check_migration_complete
sleep 5
ping_site
PG_SITE_NAME=pgsql.localhost
print_group "Create new site (Postgres)"
docker run \
--rm \
-e SITE_NAME=$PG_SITE_NAME \
-e POSTGRES_HOST=postgresql \
-e DB_ROOT_USER=postgres \
-e POSTGRES_PASSWORD=admin \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge new
check_migration_complete
SITE_NAME=$PG_SITE_NAME ping_site
print_group Backup site
docker run \
--rm \
-e WITH_FILES=1 \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge backup
MINIO_ACCESS_KEY="AKIAIOSFODNN7EXAMPLE"
MINIO_SECRET_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"
print_group Prepare S3 server
echo Start S3 server
docker run \
--name minio \
-d \
-e "MINIO_ACCESS_KEY=$MINIO_ACCESS_KEY" \
-e "MINIO_SECRET_KEY=$MINIO_SECRET_KEY" \
--network ${project_name}_default \
minio/minio server /data
echo Create bucket
docker run \
--rm \
--network ${project_name}_default \
vltgroup/s3cmd:latest \
s3cmd \
--access_key=$MINIO_ACCESS_KEY \
--secret_key=$MINIO_SECRET_KEY \
--region=us-east-1 \
--no-ssl \
--host=minio:9000 \
--host-bucket=minio:9000 \
mb s3://frappe
print_group Push backup
docker run \
--rm \
-e BUCKET_NAME=frappe \
-e REGION=us-east-1 \
-e BUCKET_DIR=local \
-e ACCESS_KEY_ID=$MINIO_ACCESS_KEY \
-e SECRET_ACCESS_KEY=$MINIO_SECRET_KEY \
-e ENDPOINT_URL=http://minio:9000 \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge push-backup
print_group Prune and restart services
docker_compose_with_args stop
docker container prune -f && docker volume prune -f
docker_compose_with_args up -d
check_health
print_group Restore backup from S3
docker run \
--rm \
-e MYSQL_ROOT_PASSWORD=admin \
-e BUCKET_NAME=frappe \
-e BUCKET_DIR=local \
-e ACCESS_KEY_ID=$MINIO_ACCESS_KEY \
-e SECRET_ACCESS_KEY=$MINIO_SECRET_KEY \
-e ENDPOINT_URL=http://minio:9000 \
-e REGION=us-east-1 \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge restore-backup
check_health
ping_site
SITE_NAME=$PG_SITE_NAME ping_site
EDGE_SITE_NAME=edge.localhost
print_group "Create new site (edge)"
docker run \
--rm \
-e SITE_NAME=$EDGE_SITE_NAME \
-e INSTALL_APPS=frappe \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge new
check_health
SITE_NAME=$EDGE_SITE_NAME ping_site
print_group Migrate edge site
docker run \
--rm \
-e MAINTENANCE_MODE=1 \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
-v ${project_name}_assets-vol:/home/frappe/frappe-bench/sites/assets \
--network ${project_name}_default \
frappe/frappe-worker:edge migrate
check_migration_complete
print_group "Restore backup S3 (overwrite)"
docker run \
--rm \
-e MYSQL_ROOT_PASSWORD=admin \
-e BUCKET_NAME=frappe \
-e BUCKET_DIR=local \
-e ACCESS_KEY_ID=$MINIO_ACCESS_KEY \
-e SECRET_ACCESS_KEY=$MINIO_SECRET_KEY \
-e ENDPOINT_URL=http://minio:9000 \
-e REGION=us-east-1 \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge restore-backup
check_migration_complete
ping_site
print_group "Check console for $SITE_NAME"
docker run \
--rm \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge console $SITE_NAME
print_group "Check console for $PG_SITE_NAME"
docker run \
--rm \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge console $PG_SITE_NAME
print_group "Check drop site for $SITE_NAME (MariaDB)"
docker run \
--rm \
-e SITE_NAME=$SITE_NAME \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge drop
print_group "Check drop site for $PG_SITE_NAME (Postgres)"
docker run \
--rm \
-e SITE_NAME=$PG_SITE_NAME \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:edge drop
print_group Check bench --help
docker run \
--rm \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
--user frappe \
frappe/frappe-worker:edge bench --help

330
tests/main.py Normal file
View File

@ -0,0 +1,330 @@
import os
import ssl
import subprocess
from enum import Enum
from functools import wraps
from time import sleep
from typing import Any, Callable, Optional
from urllib.error import HTTPError
from urllib.request import Request, urlopen
CI = os.getenv("CI")
SITE_NAME = "tests"
BACKEND_SERVICES = (
"backend",
"queue-short",
"queue-default",
"queue-long",
"scheduler",
)
def patch_print():
# Patch `print()` builtin to have nice logs when running GitHub Actions
if not CI:
return
global print
_old_print = print
def print(
*values: Any,
sep: Optional[str] = None,
end: Optional[str] = None,
file: Any = None,
flush: bool = False,
):
return _old_print(*values, sep=sep, end=end, file=file, flush=True)
class Color(Enum):
GREY = 30
RED = 31
GREEN = 32
YELLOW = 33
BLUE = 34
MAGENTA = 35
CYAN = 36
WHITE = 37
def colored(text: str, color: Color):
return f"\033[{color.value}m{text}\033[0m"
def log(text: str):
def decorator(f: Callable[..., Any]):
@wraps(f)
def wrapper(*args: Any, **kwargs: Any):
if CI:
print(f"::group::{text}")
else:
print(colored(text, Color.YELLOW))
ret = f(*args, **kwargs)
if CI:
print("::endgroup::")
return ret
return wrapper
return decorator
def run(*cmd: str):
print(colored(f"> {' '.join(cmd)}", Color.GREEN))
return subprocess.check_call(cmd)
def docker_compose(*cmd: str):
args = [
"docker",
"compose",
"-p",
"test",
"--env-file",
"example.env",
"-f",
"compose.yml",
]
if CI:
args.extend(("-f", "tests/compose.ci.yml"))
return run(*args, *cmd)
@log("Create containers")
def create_containers():
docker_compose("up", "-d")
@log("Check if backend services have connections")
def ping_links_in_backends():
for service in BACKEND_SERVICES:
for _ in range(10):
try:
docker_compose("exec", service, "healthcheck.sh")
break
except subprocess.CalledProcessError:
sleep(1)
else:
raise Exception(f"Connections healthcheck failed for service {service}")
@log("Create test site")
def create_site():
docker_compose(
"exec",
"backend",
"bench",
"new-site",
SITE_NAME,
"--mariadb-root-password",
"123",
"--admin-password",
"admin",
)
docker_compose("restart", "backend")
# This is needed to check https override
_ssl_ctx = ssl.create_default_context()
_ssl_ctx.check_hostname = False
_ssl_ctx.verify_mode = ssl.CERT_NONE
def ping_and_check_content(url: str, callback: Callable[[str], Optional[str]]):
request = Request(url, headers={"Host": SITE_NAME})
print(f"Checking {url}")
for _ in range(100):
try:
response = urlopen(request, context=_ssl_ctx)
except HTTPError as exc:
if exc.code not in (404, 502):
raise
else:
text: str = response.read().decode()
ret = callback(text)
if ret:
print(ret)
return
sleep(0.1)
raise AssertionError(f"Couldn't ping {url}")
def index_callback(text: str):
if "404 page not found" not in text:
return text[:200]
@log("Check /")
def check_index():
ping_and_check_content(url="http://127.0.0.1", callback=index_callback)
@log("Check /api/method/version")
def check_api():
ping_and_check_content(
url="http://127.0.0.1/api/method/version",
callback=lambda text: text if '"message"' in text else None,
)
@log("Check if Frappe can connect to services in backends")
def ping_frappe_connections_in_backends():
for service in BACKEND_SERVICES:
docker_compose("cp", f"tests/ping_frappe_connections.py", f"{service}:/tmp/")
docker_compose(
"exec",
service,
"/home/frappe/frappe-bench/env/bin/python",
f"/tmp/ping_frappe_connections.py",
)
@log("Check /assets")
def check_assets():
ping_and_check_content(
url="http://127.0.0.1/assets/js/frappe-web.min.js",
callback=lambda text: text[:200] if text is not None else None,
)
@log("Check /files")
def check_files():
file_name = "testfile.txt"
docker_compose(
"cp",
f"tests/{file_name}",
f"backend:/home/frappe/frappe-bench/sites/{SITE_NAME}/public/files/",
)
ping_and_check_content(
url=f"http://127.0.0.1/files/{file_name}",
callback=lambda text: text if text == "lalala\n" else None,
)
@log("Recreate with https override")
def recreate_with_https_override():
docker_compose("-f", "overrides/compose.https.yml", "up", "-d")
@log("Check / (https)")
def check_index_https():
ping_and_check_content(url="https://127.0.0.1", callback=index_callback)
@log("Stop containers")
def stop_containers():
docker_compose("down", "-v", "--remove-orphans")
@log("Recreate with ERPNext override")
def create_containers_with_erpnext_override():
args = ["-f", "overrides/compose.erpnext.yml"]
if CI:
args.extend(("-f", "tests/compose.ci-erpnext.yml"))
docker_compose(*args, "up", "-d")
@log("Create ERPNext site")
def create_erpnext_site():
docker_compose(
"exec",
"backend",
"bench",
"new-site",
SITE_NAME,
"--mariadb-root-password",
"123",
"--admin-password",
"admin",
"--install-app",
"erpnext",
)
docker_compose("restart", "backend")
@log("Check /api/method/erpnext.templates.pages.product_search.get_product_list")
def check_erpnext_api():
ping_and_check_content(
url="http://127.0.0.1/api/method/erpnext.templates.pages.product_search.get_product_list",
callback=lambda text: text if '"message"' in text else None,
)
@log("Check /assets/erpnext/js/setup_wizard.js")
def check_erpnext_assets():
ping_and_check_content(
url="http://127.0.0.1/assets/erpnext/js/setup_wizard.js",
callback=lambda text: text[:200] if text is not None else None,
)
@log("Create containers with Postgres override")
def create_containers_with_postgres_override():
docker_compose("-f", "overrides/compose.postgres.yml", "up", "-d")
@log("Create Postgres site")
def create_postgres_site():
docker_compose(
"exec", "backend", "bench", "set-config", "-g", "root_login", "postgres"
)
docker_compose(
"exec", "backend", "bench", "set-config", "-g", "root_password", "123"
)
docker_compose(
"exec",
"backend",
"bench",
"new-site",
SITE_NAME,
"--db-type",
"postgres",
"--admin-password",
"admin",
)
docker_compose("restart", "backend")
@log("Show docker compose logs")
def show_docker_compose_logs():
docker_compose("logs")
def main() -> int:
try:
patch_print()
create_containers()
ping_links_in_backends()
create_site()
check_index()
check_api()
ping_frappe_connections_in_backends()
check_assets()
check_files()
recreate_with_https_override()
check_index_https()
stop_containers()
create_containers_with_erpnext_override()
create_erpnext_site()
check_erpnext_api()
check_erpnext_assets()
stop_containers()
create_containers_with_postgres_override()
create_postgres_site()
ping_links_in_backends()
finally:
show_docker_compose_logs()
stop_containers()
print(colored("Tests successfully passed!", Color.YELLOW))
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@ -0,0 +1,26 @@
import frappe
def check_db():
doc = frappe.get_single("System Settings")
assert any(v is None for v in doc.as_dict().values()), "Database test didn't pass"
print("Database works!")
def check_cache():
key_and_name = "mytestkey", "mytestname"
frappe.cache().hset(*key_and_name, "mytestvalue")
assert frappe.cache().hget(*key_and_name) == "mytestvalue", "Cache test didn't pass"
frappe.cache().hdel(*key_and_name)
print("Cache works!")
def main() -> int:
frappe.connect(site="tests")
check_db()
check_cache()
return 0
if __name__ == "__main__":
raise SystemExit(main())

2
tests/requirements.txt Normal file
View File

@ -0,0 +1,2 @@
frappe @ git+git://github.com/frappe/frappe.git
boto3-stubs[s3]==1.20.23

View File

@ -1,44 +0,0 @@
#!/bin/bash
set -e
source tests/functions.sh
project_name="test_erpnext"
SITE_NAME="test_erpnext.localhost"
echo ::group::Setup env
cp env-example .env
sed -i -e "s/edge/test/g" .env
# shellcheck disable=SC2046
export $(cat .env)
cat .env
print_group Start services
docker-compose \
-p $project_name \
-f installation/docker-compose-common.yml \
-f installation/docker-compose-erpnext.yml \
-f installation/erpnext-publish.yml \
up -d
print_group Fix permissions
docker run \
--rm \
--user root \
-v ${project_name}_sites-vol:/sites \
-v ${project_name}_assets-vol:/assets \
-v ${project_name}_logs-vol:/logs \
frappe/erpnext-worker:test chown -R 1000:1000 /logs /sites /assets
print_group Create site
docker run \
--rm \
-e "SITE_NAME=$SITE_NAME" \
-e "INSTALL_APPS=erpnext" \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/erpnext-worker:test new
ping_site
rm .env

View File

@ -1,43 +0,0 @@
#!/bin/bash
set -e
source tests/functions.sh
project_name="test_frappe"
SITE_NAME="test_frappe.localhost"
docker_compose_with_args() {
# shellcheck disable=SC2068
docker-compose \
-p $project_name \
-f installation/docker-compose-common.yml \
-f installation/docker-compose-frappe.yml \
-f installation/frappe-publish.yml \
$@
}
echo ::group::Setup env
cp env-example .env
sed -i -e "s/edge/test/g" .env
# shellcheck disable=SC2046
export $(cat .env)
cat .env
print_group Start services
docker_compose_with_args up -d
print_group Create site
docker run \
--rm \
-e "SITE_NAME=$SITE_NAME" \
-v ${project_name}_sites-vol:/home/frappe/frappe-bench/sites \
--network ${project_name}_default \
frappe/frappe-worker:test new
ping_site
print_group Stop and remove containers
docker_compose_with_args down
rm .env

1
tests/testfile.txt Normal file
View File

@ -0,0 +1 @@
lalala