diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index f0a4032..aabb592 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -7,7 +7,7 @@ on: pull_request: jobs: - tests: + tests_client: runs-on: ${{ matrix.os }} timeout-minutes: 60 strategy: @@ -28,7 +28,6 @@ jobs: python -m pip install --upgrade pip pip install tox - name: Test using tox environment - shell: bash env: FOLDER: ${{ matrix.folder }} run: | @@ -38,3 +37,44 @@ jobs: env: FOLDER: ${{ matrix.folder }} run: tox -ecoverage + + tests_api: + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + strategy: + max-parallel: 2 + matrix: + os: [ubuntu-latest] + # In future we can add [macos-latest, windows-latest] + python-version: [3.9] + folder: ["api_server"] + services: + postgres: + image: postgres + env: + POSTGRES_USER: purplecaffeine + POSTGRES_PASSWORD: purplecaffeinepassword + POSTGRES_DB: purplecaffeine + POSTGRES_HOST_AUTH_METHOD: trust + ports: + - 5432:5432 + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - uses: actions/checkout@v3 + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@v4 + with: + python-version: ${{ matrix.python-version }} + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install tox + - name: Test using tox environment + env: + FOLDER: ${{ matrix.folder }} + run: | + tox -edjango diff --git a/api_server/README.md b/api_server/README.md index a361328..6622267 100644 --- a/api_server/README.md +++ b/api_server/README.md @@ -186,7 +186,7 @@ curl -X POST "http://localhost:8000/api/trials/" \ "metrics": [["nb_qubits", 2]], "parameters": [["OS", "ubuntu"]], "circuits": [], - "operators": [["obs", Pauli("XZYI")]], + "operators": [], "artifacts": [], "texts": [], "arrays": [], diff --git a/api_server/docker/Dockerfile.dev b/api_server/docker/Dockerfile.dev index 5173c2e..515af64 100644 --- a/api_server/docker/Dockerfile.dev +++ b/api_server/docker/Dockerfile.dev @@ -38,4 +38,5 @@ CMD cd /opt/api_server; \ python3 manage.py migrate; \ python3 manage.py createsuperuser --no-input; \ python3 manage.py collectstatic; \ + python3 manage.py test; \ exec python3 manage.py runserver 0.0.0.0:8000 diff --git a/api_server/purplecaffeine/settings.py b/api_server/purplecaffeine/settings.py index a7d4dfc..6c8d971 100644 --- a/api_server/purplecaffeine/settings.py +++ b/api_server/purplecaffeine/settings.py @@ -43,6 +43,13 @@ "core", "health_check", "drf_spectacular", + "django_nose", +] + +TEST_RUNNER = "django_nose.NoseTestSuiteRunner" +NOSE_ARGS = [ + "--cover-erase", + "--cover-package=purplecaffeine", ] MIDDLEWARE = [ diff --git a/api_server/requirements.txt b/api_server/requirements.txt index f205a41..017ebd3 100644 --- a/api_server/requirements.txt +++ b/api_server/requirements.txt @@ -7,3 +7,4 @@ gunicorn==21.2.0 django-health-check==3.17.0 whitenoise==6.5.0 drf-spectacular==0.26.4 +django-nose==1.4.7 diff --git a/api_server/tests.py b/api_server/tests.py new file mode 100644 index 0000000..71544de --- /dev/null +++ b/api_server/tests.py @@ -0,0 +1,106 @@ +"""Tests file.""" +import json +from django.contrib.auth.models import User +from django.urls import reverse +from django.test import TestCase + + +class UnitTests(TestCase): + """Unit tests.""" + + def setUp(self) -> None: + admin_username = "admin" + admin_pass = "admin" + User.objects.create_superuser(admin_username, "admin@admin.com", admin_pass) + + def get_token(self): + """Get token.""" + + data = {"username": "admin", "password": "admin"} + + url = reverse("token_obtain_pair") + login = self.client.post(url, data=data, content_type="application/json") + return json.loads(login.content)["access"] + + def test_get_token(self): + """ + Ensure we can get a token. + """ + + data = {"username": "admin", "password": "admin"} + + url = reverse("token_obtain_pair") + login = self.client.post(url, data=data, content_type="application/json") + self.assertEqual(login.status_code, 200) + + token_refresh = json.loads(login.content)["refresh"] + + url = reverse("token_refresh") + refresh = self.client.post( + url, data={"refresh": f"{token_refresh}"}, content_type="application/json" + ) + self.assertEqual(refresh.status_code, 200) + + token_access = json.loads(login.content)["access"] + + url = reverse("token_verify") + verify = self.client.post( + url, data={"token": f"{token_access}"}, content_type="application/json" + ) + self.assertEqual(verify.status_code, 200) + + def test_get_swagger(self): + """ + Ensure we can get a swagger. + """ + + url = reverse("swagger-ui") + response = self.client.get(url) + self.assertEqual(response.status_code, 200) + + def test_trials(self): + """Tests getting trials.""" + + data = { + "name": "My super experiment", + "description": "My super experiments desciption", + "storage": {"__type__": "PurpleCaffeineBackend"}, + "metrics": [["nb_qubits", 2]], + "parameters": [["OS", "ubuntu"]], + "circuits": [], + "operators": [], + "artifacts": [], + "texts": [], + "arrays": [], + "tags": [], + } + post = self.client.post( + "/api/trials/", + data=data, + headers={"Authorization": f" Bearer {self.get_token()}"}, + content_type="application/json", + ) + self.assertEqual(post.status_code, 201) + + get_all = self.client.get( + "/api/trials/", + headers={"Authorization": f" Bearer {self.get_token()}"}, + content_type="application/json", + ) + self.assertEqual(get_all.status_code, 200) + self.assertIsInstance(json.loads(get_all.content)["results"], list) + + get_one = self.client.get( + "/api/trials/1/", + headers={"Authorization": f" Bearer {self.get_token()}"}, + content_type="application/json", + ) + self.assertEqual(get_one.status_code, 200) + self.assertEqual(json.loads(get_one.content)["id"], 1) + + delete = self.client.delete( + "/api/trials/1/", + headers={"Authorization": f" Bearer {self.get_token()}"}, + content_type="application/json", + ) + self.assertEqual(delete.status_code, 204) diff --git a/docs/guides/04_setup_api.ipynb b/docs/guides/04_setup_api.ipynb index bf9689a..cac24dc 100644 --- a/docs/guides/04_setup_api.ipynb +++ b/docs/guides/04_setup_api.ipynb @@ -209,7 +209,7 @@ " \"metrics\": [[\"nb_qubits\", 2]],\n", " \"parameters\": [[\"OS\", \"ubuntu\"]],\n", " \"circuits\": [],\n", - " \"operators\": [[\"obs\", Pauli(\"XZYI\")]],\n", + " \"operators\": [],\n", " \"artifacts\": [],\n", " \"texts\": [],\n", " \"arrays\": [],\n", @@ -236,7 +236,7 @@ " \"metrics\": [[\"nb_qubits\", 2]],\n", " \"parameters\": [[\"OS\", \"ubuntu\"]],\n", " \"circuits\": [],\n", - " \"operators\": [[\"obs\", Pauli(\"XZYI\")]],\n", + " \"operators\": [],\n", " \"artifacts\": [],\n", " \"texts\": [],\n", " \"arrays\": [],\n", diff --git a/tox.ini b/tox.ini index 3750f07..153c86e 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] minversion = 3.8 -envlist = py38, py39, py310, lint, coverage, black, ecosystem, docs +envlist = py38, py39, py310, lint, coverage, django, lint, black, ecosystem, docs, jupyter skipsdist = True [testenv] @@ -23,6 +23,13 @@ commands = coverage3 run -m unittest discover -s {env:FOLDER:} -v coverage3 report --fail-under=80 +[testenv:django] +basepython = python3 +commands = + pip check {env:FOLDER:} + coverage3 run {env:FOLDER:}/manage.py test {env:FOLDER:}/ + coverage3 report --fail-under=80 + [testenv:lint] envdir = .tox/lint commands =