Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add initial testing #26

Merged
merged 32 commits into from
Feb 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
0e0d13d
try get initial tests working
hmacdope Feb 8, 2024
b20382a
add in env file
hmacdope Feb 8, 2024
c0d67fb
fix names and rename file
hmacdope Feb 8, 2024
c5a819c
fix
hmacdope Feb 8, 2024
b17c644
fix again
hmacdope Feb 8, 2024
73a9418
move to ci file
hmacdope Feb 8, 2024
0d964ef
Revert "move to ci file"
hmacdope Feb 8, 2024
129f699
collapse to one file
hmacdope Feb 8, 2024
d349469
fix indents
hmacdope Feb 8, 2024
2474c43
try some stuff
hmacdope Feb 8, 2024
1294206
add ci to correct path
hmacdope Feb 8, 2024
4507072
fix TTY issues
hmacdope Feb 8, 2024
298cb10
try waiting
hmacdope Feb 8, 2024
5f77ff3
try with healthcheck instead
hmacdope Feb 8, 2024
1632b52
try making sure service is healthy
hmacdope Feb 8, 2024
472a5f7
add initial testing
hmacdope Feb 8, 2024
28c2958
add updates
hmacdope Feb 9, 2024
d5a16fb
make model tests work
hmacdope Feb 9, 2024
ed5f687
make tests even better
hmacdope Feb 9, 2024
d40eb8c
improve again
hmacdope Feb 9, 2024
74bf28a
get tests partially working
hmacdope Feb 9, 2024
0af693b
try
hmacdope Feb 9, 2024
81f60b6
inject OE license
hmacdope Feb 9, 2024
29d9ee2
fix settings stuff
hmacdope Feb 9, 2024
b91d3a2
HOLY GUACAMOLE it was the OE version
hmacdope Feb 9, 2024
8e54361
fix wf
hmacdope Feb 9, 2024
ca40809
gix path?
hmacdope Feb 9, 2024
9ead9ab
Update ci.yaml
hmacdope Feb 11, 2024
dd9b7cb
Update ci.yaml
hmacdope Feb 11, 2024
5882376
Update test_views.py
hmacdope Feb 11, 2024
b50f232
Update test_views.py
hmacdope Feb 11, 2024
40411e4
Update test_views.py
hmacdope Feb 11, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
name: ci

on:
push:
branches:
- "main"
pull_request:
branches:
- "main"
schedule:
# Nightly tests run on main by default:
# Scheduled workflows run on the latest commit on the default or base branch.
# (from https://help.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule)
- cron: "0 0 * * *"
workflow_dispatch:

concurrency:
group: "${{ github.workflow }}-${{ github.ref }}"
cancel-in-progress: true

defaults:
run:
shell: bash -l {0}

jobs:
build:
runs-on: ubuntu-latest

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Install docker-compose
run: |
sudo apt-get update
sudo apt-get install -y docker-compose

- name: Copy example env file
run: |
cp devtools/deployment/.env.example .env

- name: Make OpenEye directory
run: |
mkdir -p ~/.OpenEye

- name: Copy OpenEye license file
env:
OE_LICENSE: ${{ secrets.OE_LICENSE }}
run: |
echo "$OE_LICENSE" > ~/.OpenEye/oe_license.txt

- name: Build containers
run: |
docker-compose -f docker-compose-dev.yml build --build-arg USER_ID=$(id -u) --build-arg GROUP_ID=$(id -g)
docker container ls
docker-compose -f docker-compose-dev.yml up -d

- name: Chown volume
run: |
ls -alsh
ls -alsh argos
sudo chown -R $(id -u):$(id -g) argos/pdb_data

- name: Run tests
run: |
docker-compose -f docker-compose-dev.yml exec -T web bash -c "cd argos && /opt/conda/bin/python manage.py test --no-input"
17 changes: 15 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
# Use the conda-forge base image with Python
FROM mambaorg/micromamba:jammy


ARG USER_ID
ARG GROUP_ID

USER root

RUN addgroup --gid $GROUP_ID user
RUN adduser --disabled-password --gecos '' --uid $USER_ID --gid $GROUP_ID user
USER user


# set environment variables
ENV PYTHONUNBUFFERED 1

Expand All @@ -13,15 +24,17 @@ COPY . /argos
RUN micromamba config append channels conda-forge
RUN micromamba config append channels openeye

COPY --chown=$MAMBA_USER:$MAMBA_USER devtools/conda-envs/argos-ubuntu-latest.yml /tmp/env.yaml
COPY --chown=user:user devtools/conda-envs/argos-ubuntu-latest.yml /tmp/env.yaml

RUN micromamba install -y -n base git -f /tmp/env.yaml && \
micromamba clean --all --yes

USER root
RUN mkdir /openeye
RUN chown -R user:user /openeye
RUN mkdir /argos/pdb_data
USER $MAMBA_USER
RUN chown -R user:user /argos/pdb_data
USER user
ENV OE_LICENSE=/openeye/oe_license.txt


Expand Down
17 changes: 17 additions & 0 deletions argos/argos/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'django_cleanup.apps.CleanupConfig',
'argos_viewer.apps.ArgosViewerConfig',

]
Expand Down Expand Up @@ -89,6 +90,7 @@

DATABASES = {
'default': env.db(),

}


Expand Down Expand Up @@ -146,3 +148,18 @@

# Redirect to home URL after login (Default redirects to /accounts/profile/)
LOGIN_REDIRECT_URL = '/'


LOGGING = {
"version": 1,
"disable_existing_loggers": False,
"handlers": {
"console": {"class": "logging.StreamHandler"},
},
"loggers": {
"django": {
"handlers": ["console"],
"level": "INFO",
},
}
}
16 changes: 15 additions & 1 deletion argos/argos_viewer/models.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,26 @@
from typing import Any
from django.db import models
from django.core.validators import FileExtensionValidator

import os

class PDBFile(models.Model):
file = models.FileField(validators=[FileExtensionValidator(['pdb'])], upload_to="pdb_data")

def delete(self, *args, **kwargs):
# Delete the file when the instance is deleted
if self.file:
if os.path.isfile(self.file.path):
os.remove(self.file.path)
super(PDBFile, self).delete(*args, **kwargs)

class TargetPDBFile(models.Model):
pdb_file = models.ForeignKey(PDBFile, on_delete=models.CASCADE)
target = models.CharField(max_length=200)
upload_date = models.DateTimeField(auto_now_add=True)


def delete(self, *args, **kwargs):
# Delete the associated PDBFile instance, which should trigger its delete method
if self.pdb_file:
self.pdb_file.delete()
super(TargetPDBFile, self).delete(*args, **kwargs)

This file was deleted.

3 changes: 0 additions & 3 deletions argos/argos_viewer/tests.py

This file was deleted.

Empty file.
43 changes: 43 additions & 0 deletions argos/argos_viewer/tests/test_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from django.test import TestCase
from argos_viewer.models import PDBFile, TargetPDBFile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.utils import timezone
import os

class PDBFileModelTest(TestCase):
def setUp(self):
self.file = SimpleUploadedFile("test.pdb", b"pdb file content")
self.pdb_file = PDBFile.objects.create(file=self.file)


def test_pdb_file_created(self):
self.assertTrue(os.path.exists(self.pdb_file.file.path))

def test_file_extension(self):
self.assertEqual(self.pdb_file.file.name.split(".")[-1], "pdb")

class TargetPDBFileModelTest(TestCase):
def setUp(self):
self.file = SimpleUploadedFile("test.pdb", b"pdb file content")
self.pdb_file = PDBFile.objects.create(file=self.file)
self.target_pdb_file = TargetPDBFile.objects.create(pdb_file=self.pdb_file, target="test_target", upload_date=timezone.now())

def tearDown(self):
if os.path.exists(self.target_pdb_file.pdb_file.file.path):
os.remove(self.target_pdb_file.pdb_file.file.path)

def test_target_pdb_file_created(self):
self.assertTrue(TargetPDBFile.objects.exists())

def test_target(self):
self.assertEqual(self.target_pdb_file.target, "test_target")

def test_upload_date(self):
self.assertIsNotNone(self.target_pdb_file.upload_date)

def test_pdb_file_deletion_on_target_pdb_file_deletion(self):
self.target_pdb_file.delete()
self.assertFalse(os.path.exists(self.pdb_file.file.path))



6 changes: 6 additions & 0 deletions argos/argos_viewer/tests/test_oe_license.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from django.test import TestCase

class OELicenseTests(TestCase):
def test_oechem_is_licensed(self):
from asapdiscovery.data.openeye import oechem
self.assertTrue(oechem.OEChemIsLicensed())
28 changes: 28 additions & 0 deletions argos/argos_viewer/tests/test_urls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from django.test import SimpleTestCase
from django.urls import reverse, resolve
from argos_viewer.views import home, upload_sucessful, TargetPDBListView, target_pdb_detail_view, failed, no_fitness_data

class TestUrls(SimpleTestCase):
def test_home_url_resolves(self):
url = reverse('home')
self.assertEqual(resolve(url).func, home)

def test_upload_sucessful_url_resolves(self):
url = reverse('upload_sucessful')
self.assertEqual(resolve(url).func, upload_sucessful)

def test_pdb_files_url_resolves(self):
url = reverse('pdb_files')
self.assertEqual(resolve(url).func.view_class, TargetPDBListView)

def test_detail_url_resolves(self):
url = reverse('detail', args=[1]) # assuming pk=1
self.assertEqual(resolve(url).func, target_pdb_detail_view)

def test_failed_url_resolves(self):
url = reverse('failed')
self.assertEqual(resolve(url).func, failed)

def test_no_fitness_data_url_resolves(self):
url = reverse('no_fitness_data', args=['target_name'])
self.assertEqual(resolve(url).func, no_fitness_data)
55 changes: 55 additions & 0 deletions argos/argos_viewer/tests/test_views.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
from django.test import TestCase, Client, RequestFactory
from django.urls import reverse
from argos_viewer.models import PDBFile, TargetPDBFile
from django.core.files.uploadedfile import SimpleUploadedFile
from django.utils import timezone
from django.contrib.auth.models import User
from asapdiscovery.data.testing.test_resources import fetch_test_file


class ViewTests(TestCase):
def setUp(self):
self._test_file = fetch_test_file("Mpro-P2660_0A_bound.pdb")
with open(self._test_file, "r") as f:
self._file_contents = f.read()
# Create a user
self.user = User.objects.create_user(username='testuser', password='12345')
self.file = SimpleUploadedFile("test.pdb", self._file_contents.encode())
self.pdb_file = PDBFile.objects.create(file=self.file)
self.target_pdb_file = TargetPDBFile.objects.create(pdb_file=self.pdb_file, target="SARS-CoV-2-Mpro", upload_date=timezone.now())

def test_index_view(self):
response = self.client.get(reverse('index'))
self.assertEqual(response.status_code, 302) # Redirects to home

def test_home_view_GET(self):
self.client.force_login(self.user)
response = self.client.get(reverse('home'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'argos_viewer/home.html')

def test_upload_successful_view(self):
self.client.force_login(self.user)
response = self.client.get(reverse('upload_sucessful'))
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'upload worked!')


def test_target_pdb_detail_view_GET(self):
self.client.force_login(self.user)
response = self.client.get(reverse('detail', args=[self.target_pdb_file.pk]), follow=True)
self.assertEqual(response.status_code, 200)

def test_failed_view_GET(self):
self.client.force_login(self.user)
response = self.client.get(reverse('failed'))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'argos_viewer/failed.html')

def test_no_fitness_data_view_GET(self):
self.client.force_login(self.user)
response = self.client.get(reverse('no_fitness_data', args=['target_name']))
self.assertEqual(response.status_code, 200)
self.assertTemplateUsed(response, 'argos_viewer/no_fitness_data.html')

# Add tests for POST requests as well if necessary
13 changes: 8 additions & 5 deletions argos/argos_viewer/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
from asapdiscovery.data.fitness import target_has_fitness_data
import tempfile

import logging

logger = logging.getLogger('django')

def index(request):
context = {}
return redirect("home")
Expand Down Expand Up @@ -74,14 +78,13 @@ def target_pdb_detail_view(request, pk):
target_kwargs={"target_name": "unknown"},
)

tf = tempfile.NamedTemporaryFile()
tf = tempfile.NamedTemporaryFile()
html_viz = HTMLVisualizer(
[c.ligand.to_oemol()], [tf], obj.target, c.target.to_oemol(), color_method="fitness", align=False
)
# align=True is broken, see https://github.com/choderalab/asapdiscovery/issues/709
[c.ligand.to_oemol()], [tf], obj.target, c.target.to_oemol(), color_method="fitness", align=True)
html = html_viz.make_poses_html()[0]
logger.debug("Made pose html")
except Exception as e:
print(f"rendering failed with exception {e}")
logger.error(f"rendering failed with exception {e}")
return redirect("failed")

return HttpResponse(html)
Expand Down
15 changes: 11 additions & 4 deletions devtools/conda-envs/argos-ubuntu-latest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,27 @@ dependencies:

# Base depends
- pip
- python =3.10
- git
- python >=3.10,<3.11


# argos deps
- django
- gunicorn
- django-cleanup


# Testing
- pytest
- pytest-cov
- pooch

# asapdiscovery deps

# Others
- appdirs
- openeye-toolkits
- openeye-toolkits <2023.2.3
- pydantic >=1.10.8,<2.0.0a0


# data
- requests
- boto3
Expand Down
2 changes: 1 addition & 1 deletion devtools/deployment/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ DATABASE_URL=postgresql://django_traefik:django_traefik@db:5432/django_traefik
HOST_DOMAIN=localhost
POSTGRES_USER=django_traefik
POSTGRES_PASSWORD=django_traefik
POSTGRES_DB=django_traefik
POSTGRES_DB=django_traefik
Loading
Loading