Skip to content

Commit

Permalink
Merge pull request #725 from CharlesSheelam/smoke-testing
Browse files Browse the repository at this point in the history
feat: add cypress end to end tests
  • Loading branch information
alee authored Sep 3, 2024
2 parents f515d6a + ade645d commit 99c7478
Show file tree
Hide file tree
Showing 49 changed files with 908 additions and 91 deletions.
33 changes: 25 additions & 8 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,34 @@
name: E2E Tests

on:
workflow_dispatch # disabled pending db seeding
# push:
# branches: [ main ]
# pull_request:
# branches: [ main ]
push:
branches: [ main ]
pull_request:
branches: [ main ]

jobs:
build:
e2e:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: build containers and run cypress e2e tests
# TODO: seed the database with a sparse(r) dump so there are pages to test..

- name: deploy services in e2e mode
run: make e2e

- name: run e2e tests
uses: cypress-io/github-action@v6
with:
working-directory: e2e
wait-on: "http://localhost:8000"
wait-on-timeout: 300

- name: display service logs
if: failure()
run: docker compose -f docker-compose.yml -f e2e.yml logs

- name: upload cypress videos
if: failure()
uses: actions/upload-artifact@v4
with:
name: cypress-videos
path: e2e/cypress/videos
24 changes: 18 additions & 6 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ release-version: .env
.PHONY: docker-compose.yml
docker-compose.yml: base.yml dev.yml staging.yml prod.yml config.mk $(PGPASS_PATH) release-version
case "$(DEPLOY_ENVIRONMENT)" in \
dev|staging|e2e) docker compose -f base.yml -f $(DEPLOY_ENVIRONMENT).yml config > docker-compose.yml;; \
dev|staging) docker compose -f base.yml -f $(DEPLOY_ENVIRONMENT).yml config > docker-compose.yml;; \
prod) docker compose -f base.yml -f staging.yml -f $(DEPLOY_ENVIRONMENT).yml config > docker-compose.yml;; \
*) echo "invalid environment. must be either dev, staging or prod" 1>&2; exit 1;; \
esac
Expand Down Expand Up @@ -140,9 +140,21 @@ clean_deploy: clean
test: build
docker compose run --rm server /code/deploy/test.sh

# e2e testing setup

E2E_SHARED_DIR=${DOCKER_SHARED_DIR}/e2e
E2E_BACKUPS_PATH=${E2E_SHARED_DIR}/backups
E2E_REPO_PATH=${E2E_BACKUPS_PATH}/repo

$(E2E_REPO_PATH):
mkdir -p $(E2E_BACKUPS_PATH)
wget -c ${BORG_REPO_URL} -P $(E2E_BACKUPS_PATH)
tar -Jxf $(E2E_BACKUPS_PATH)/repo.tar.xz -C $(E2E_BACKUPS_PATH)

.PHONY: e2e
e2e: DEPLOY_ENVIRONMENT=e2e
e2e: build
docker compose run server inv collectstatic
docker compose run --rm e2e npm run test
docker compose down
e2e: docker-compose.yml secrets $(DOCKER_SHARED_DIR) $(E2E_REPO_PATH)
docker compose -f docker-compose.yml -f e2e.yml up -d --build
docker compose -f docker-compose.yml -f e2e.yml exec server bash -c "\
inv borg.restore --force && \
./manage.py migrate && \
inv prepare"
4 changes: 2 additions & 2 deletions django/core/jinja2/common.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -186,9 +186,9 @@
<form class="mb-3" action="{{ search_url }}" method="get">
<label class="sr-only" for="search-query">Search</label>
<div class="input-group">
<input id="search-query" class="form-control" name="query" type="search" value=""
<input id="search-query" data-cy="search-bar" class="form-control" name="query" type="search" value=""
placeholder="{{ placeholder }}">
<button type="submit" class="btn btn-primary">
<button type="submit" data-cy="search-button" class="btn btn-primary">
<i class="fas fa-search px-1"></i>
</button>
</div>
Expand Down
2 changes: 1 addition & 1 deletion django/core/jinja2/core/events/list.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@


{% macro render_event(item, detail_url_name) %}
<div class="card mb-3">
<div class="card mb-3" data-cy="event-result">
<div class='card-body'>
<div class='row'>
<div class='col-8'>
Expand Down
2 changes: 1 addition & 1 deletion django/core/jinja2/core/jobs/list.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
{% endblock ogp_tags %}

{% macro render_job(item, detail_url_name) %}
<div class="card mb-3">
<div class="card mb-3" data-cy="job-result">
<div class='card-body'>
<div class='row'>
<div class='col-8'>
Expand Down
2 changes: 1 addition & 1 deletion django/core/jinja2/core/member_profiles/retrieve.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@
<div class='card-metadata'>
<div class='card-body'>
{% if has_change_perm %}
<a href="{{ profile.get_edit_url() }}" class='btn btn-primary w-100 my-1'>
<a href="{{ profile.get_edit_url() }}" class='btn btn-primary w-100 my-1' data-cy="edit-profile">
Edit Profile</a>
<a href="{{ url('library:codebase-add') }}" class="btn btn-secondary w-100 my-1">
Publish a model
Expand Down
24 changes: 22 additions & 2 deletions django/core/settings/e2e.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,25 @@
from .dev import *
from .test import *

DEPLOY_ENVIRONMENT = Environment.TEST
DEBUG = True

DJANGO_VITE_DEV_MODE = False

SHARE_DIR = path.realpath("/shared/e2e")
LIBRARY_ROOT = path.join(SHARE_DIR, "library")
LIBRARY_PREVIOUS_ROOT = path.join(SHARE_DIR, ".latest")
REPOSITORY_ROOT = path.join(BASE_DIR, "repository")
BACKUP_ROOT = path.join(SHARE_DIR, "backups")
BORG_ROOT = path.join(BACKUP_ROOT, "repo")
EXTRACT_ROOT = path.join(SHARE_DIR, "extract")
MEDIA_ROOT = path.join(SHARE_DIR, "media")

DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql",
"NAME": os.getenv("DB_NAME"),
"USER": os.getenv("DB_USER"),
"PASSWORD": read_secret("db_password", os.getenv("DB_PASSWORD")),
"HOST": "e2edb",
"PORT": os.getenv("DB_PORT"),
}
}
13 changes: 9 additions & 4 deletions django/curator/invoke_tasks/borg.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,14 +203,19 @@ def restore_database(

@task()
def restore(
ctx, repo=settings.BORG_ROOT, archive=None, target_database=db._DEFAULT_DATABASE
ctx,
repo=settings.BORG_ROOT,
archive=None,
target_database=db._DEFAULT_DATABASE,
force=False,
):
"""Restore the library files, media files and database to the state given in the borg repo at path REPO
using archive ARCHIVE. The target_database argument is for testing so a different database can be used to
make sure the database is getting restored properly"""
confirm(
"Are you sure you want to restore the database and all file content (y/n)? "
)
if not force:
confirm(
"Are you sure you want to restore the database and all file content (y/n)? "
)
with tempfile.TemporaryDirectory(dir=settings.SHARE_DIR) as working_directory:
_restore(
ctx,
Expand Down
4 changes: 2 additions & 2 deletions django/curator/invoke_tasks/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def create_pgpass_file(ctx, db_key=_DEFAULT_DATABASE, force=False):
if os.path.isfile(pgpass_path) and not force:
return
with open(pgpass_path, "w+") as pgpass:
pgpass.write("db:*:*:{db_user}:{db_password}\n".format(**db_config))
pgpass.write("{db_host}:*:*:{db_user}:{db_password}\n".format(**db_config))
ctx.run("chmod 0600 ~/.pgpass")


Expand Down Expand Up @@ -132,7 +132,7 @@ def restore_from_dump(
cat_cmd = "zcat"
drop(ctx, database=target_database, create=True)
ctx.run(
"{cat_cmd} {dumpfile} | psql -w -q -o restore-from-dump-log.txt -h db {db_name} {db_user}".format(
"{cat_cmd} {dumpfile} | psql -w -q -o restore-from-dump-log.txt -h {db_host} {db_name} {db_user}".format(
cat_cmd=cat_cmd, dumpfile=dumpfile, **db_config
),
echo=True,
Expand Down
2 changes: 1 addition & 1 deletion django/library/jinja2/library/codebases/macros.jinja
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
{% endmacro %}

{% macro render_codebase_result(codebase) %}
<div class="search-result">
<div data-cy="codebase-search-result" class="search-result">
<div class="row">
<div class="col-md-12 col-lg-3">
<a href="{{ codebase.get_absolute_url() }}">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,18 +262,18 @@
{% if release.live %}
{% if invite %}
{# direct release download #}
<a id="releaseDownload" class='btn btn-primary my-1 w-100' data-name="download" rel='nofollow' href="{{ release.get_download_url() }}">
<a id="releaseDownload" data-cy="release-version" class='btn btn-primary my-1 w-100' data-name="download" rel='nofollow' href="{{ release.get_download_url() }}">
<i class='fas fa-download'></i> Download Version {{ release.version_number }}
</a>
{% else %}
{# use survey form #}
<div id='download-form' data-user-data="{{ get_download_request_metadata(request.user) }}"
<div id='download-form' data-cy="release-version" data-user-data="{{ get_download_request_metadata(request.user) }}"
data-version-number="{{ release.version_number }}"
data-identifier="{{ codebase.identifier }}"></div>
{% endif %}
{% else %}
{# direct review archive download #}
<a rel='nofollow' class='btn btn-primary my-1 w-100' href="{{ release.get_review_download_url() }}">
<a rel='nofollow' data-cy="release-version" class='btn btn-primary my-1 w-100' href="{{ release.get_review_download_url() }}">
Download for Review
</a>
{% endif %}
Expand Down
53 changes: 35 additions & 18 deletions e2e.yml
Original file line number Diff line number Diff line change
@@ -1,27 +1,44 @@
services:
e2e:
image: comses/cypress
build: e2e
environment:
- CYPRESS_baseUrl=http://server:8000
db:
image: alpine # disable the normal db container
command: tail -f /dev/null
healthcheck:
disable: true
e2edb:
image: postgis/postgis:15-3.4
secrets:
- db_password # re-using the same db password
volumes:
- ./e2e/cypress:/code/cypress
- ./e2e/cypress.config.js:/code/cypress.config.js
- ./django/deploy/wait-for-it.sh:/code/wait-for-it.sh
depends_on:
- server
- ./build/secrets/db_password:/run/secrets/db_password
healthcheck:
test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
interval: 30s
timeout: 5s
retries: 5
environment:
POSTGRES_USER: "${DB_USER}"
POSTGRES_DB: "${DB_NAME}"
POSTGRES_PASSWORD_FILE: /run/secrets/db_password
vite:
volumes:
- ./frontend:/code
command: ["npm", "run", "build"]
environment:
NODE_ENV: "e2e"
server:
image: comses/server:dev
volumes:
- ./django:/code
- ./docs:/docs
depends_on:
db:
condition: service_started
e2edb:
condition: service_healthy
elasticsearch:
condition: service_healthy
redis:
condition: service_started
vite:
condition: service_completed_successfully
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000"]
interval: 30s
timeout: 10s
retries: 5
environment:
DJANGO_SETTINGS_MODULE: "core.settings.e2e"
ports:
- "127.0.0.1:8000:8000"
12 changes: 12 additions & 0 deletions e2e/.prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"$schema": "https://json.schemastore.org/prettierrc",
"semi": true,
"tabWidth": 2,
"useTabs": false,
"singleQuote": false,
"printWidth": 100,
"trailingComma": "es5",
"bracketSpacing": true,
"bracketSameLine": false,
"arrowParens": "avoid"
}
14 changes: 0 additions & 14 deletions e2e/Dockerfile

This file was deleted.

4 changes: 2 additions & 2 deletions e2e/cypress.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
baseUrl: "http://localhost:8000",
specPattern: ["cypress/e2e/**/*.spec.ts"],
specPattern: ["cypress/tests/**/*.spec.ts"],
supportFile: false,
screenshotOnRunFailure: false,
video: false,
video: true,
}
});
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added e2e/cypress/fixtures/codebase/testCodebase.zip
Binary file not shown.
22 changes: 22 additions & 0 deletions e2e/cypress/fixtures/codebase/testCodebase/pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
#generated from chatgpt

[tool.poetry]
name = "logistic-growth-model"
version = "0.1.0"
description = "A simple logistic growth model simulation"
authors = ["Your Name <[email protected]>"]
license = "MIT"
readme = "README.md"

[tool.poetry.dependencies]
python = "^3.8"
numpy = "^1.21.0"
matplotlib = "^3.4.2"

[tool.poetry.dev-dependencies]
pytest = "^6.2.4"

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

33 changes: 33 additions & 0 deletions e2e/cypress/fixtures/codebase/testCodebase/src/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#generated from chatgpt

import numpy as np
import matplotlib.pyplot as plt

# Logistic growth model parameters
r = 0.1 # Growth rate
K = 1000 # Carrying capacity
P0 = 10 # Initial population
t_max = 100 # Time duration
dt = 1 # Time step

# Time array
time = np.arange(0, t_max, dt)

# Population array
population = np.zeros_like(time)
population[0] = P0

# Logistic growth model calculation
for t in range(1, len(time)):
population[t] = population[t-1] + r * population[t-1] * (1 - population[t-1] / K) * dt

# Plot the results
plt.figure(figsize=(10, 6))
plt.plot(time, population, label='Population')
plt.xlabel('Time')
plt.ylabel('Population')
plt.title('Logistic Growth Model')
plt.legend()
plt.grid(True)
plt.show()

Loading

0 comments on commit 99c7478

Please sign in to comment.