From 7f52c705d7998b6707113fe6d5e637feb6fafefc Mon Sep 17 00:00:00 2001 From: Ernesto Rico Schmidt <ernesto@helsinki.at> Date: Mon, 8 May 2023 15:58:09 -0400 Subject: [PATCH] Add tests with pytests - Add `pytest-factoryboy` dependency - Add pytest options - Add factories for User, Host, Image, FundingCategory, Type, Show, RRule, Schedule and Timeslot - Add pytest fixtures - Add tests for Schedules, Shows, Timeslots ma Users --- poetry.lock | 312 ++++++++++++++++++++------------ program/tests/factories.py | 83 +++++++++ program/tests/test_schedules.py | 220 ++++++++++++++++++++++ program/tests/test_shows.py | 86 +++++++++ program/tests/test_timeslots.py | 95 ++++++++++ program/tests/test_users.py | 162 +++++++++++++++++ pyproject.toml | 10 + 7 files changed, 854 insertions(+), 114 deletions(-) create mode 100644 program/tests/factories.py create mode 100644 program/tests/test_schedules.py create mode 100644 program/tests/test_shows.py create mode 100644 program/tests/test_timeslots.py create mode 100644 program/tests/test_users.py diff --git a/poetry.lock b/poetry.lock index 09f26e2d..adea804e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.4.0 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.4.2 and should not be changed by hand. [[package]] name = "asgiref" @@ -17,51 +17,65 @@ tests = ["mypy (>=0.800)", "pytest", "pytest-asyncio"] [[package]] name = "attrs" -version = "22.2.0" +version = "23.1.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" files = [ - {file = "attrs-22.2.0-py3-none-any.whl", hash = "sha256:29e95c7f6778868dbd49170f98f8818f78f3dc5e0e37c0b1f474e3561b240836"}, - {file = "attrs-22.2.0.tar.gz", hash = "sha256:c9227bfc2f01993c03f68db37d1d15c9690188323c067c641f1a35ca58185f99"}, + {file = "attrs-23.1.0-py3-none-any.whl", hash = "sha256:1f28b4522cdc2fb4256ac1a020c78acf9cba2c6b461ccd2c126f3aa8e8335d04"}, + {file = "attrs-23.1.0.tar.gz", hash = "sha256:6279836d581513a26f1bf235f9acd333bc9115683f14f7e8fae46c98fc50e015"}, ] [package.extras] -cov = ["attrs[tests]", "coverage-enable-subprocess", "coverage[toml] (>=5.3)"] -dev = ["attrs[docs,tests]"] -docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope.interface"] -tests = ["attrs[tests-no-zope]", "zope.interface"] -tests-no-zope = ["cloudpickle", "cloudpickle", "hypothesis", "hypothesis", "mypy (>=0.971,<0.990)", "mypy (>=0.971,<0.990)", "pympler", "pympler", "pytest (>=4.3.0)", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-mypy-plugins", "pytest-xdist[psutil]", "pytest-xdist[psutil]"] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[docs,tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-no-zope = ["cloudpickle", "hypothesis", "mypy (>=1.1.1)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "pytest-xdist[psutil]"] [[package]] name = "black" -version = "22.12.0" +version = "23.3.0" description = "The uncompromising code formatter." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "black-22.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9eedd20838bd5d75b80c9f5487dbcb06836a43833a37846cf1d8c1cc01cef59d"}, - {file = "black-22.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:159a46a4947f73387b4d83e87ea006dbb2337eab6c879620a3ba52699b1f4351"}, - {file = "black-22.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d30b212bffeb1e252b31dd269dfae69dd17e06d92b87ad26e23890f3efea366f"}, - {file = "black-22.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:7412e75863aa5c5411886804678b7d083c7c28421210180d67dfd8cf1221e1f4"}, - {file = "black-22.12.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c116eed0efb9ff870ded8b62fe9f28dd61ef6e9ddd28d83d7d264a38417dcee2"}, - {file = "black-22.12.0-cp37-cp37m-win_amd64.whl", hash = "sha256:1f58cbe16dfe8c12b7434e50ff889fa479072096d79f0a7f25e4ab8e94cd8350"}, - {file = "black-22.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77d86c9f3db9b1bf6761244bc0b3572a546f5fe37917a044e02f3166d5aafa7d"}, - {file = "black-22.12.0-cp38-cp38-win_amd64.whl", hash = "sha256:82d9fe8fee3401e02e79767016b4907820a7dc28d70d137eb397b92ef3cc5bfc"}, - {file = "black-22.12.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:101c69b23df9b44247bd88e1d7e90154336ac4992502d4197bdac35dd7ee3320"}, - {file = "black-22.12.0-cp39-cp39-win_amd64.whl", hash = "sha256:559c7a1ba9a006226f09e4916060982fd27334ae1998e7a38b3f33a37f7a2148"}, - {file = "black-22.12.0-py3-none-any.whl", hash = "sha256:436cc9167dd28040ad90d3b404aec22cedf24a6e4d7de221bec2730ec0c97bcf"}, - {file = "black-22.12.0.tar.gz", hash = "sha256:229351e5a18ca30f447bf724d007f890f97e13af070bb6ad4c0a441cd7596a2f"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, + {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, + {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, + {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, + {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, + {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, + {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, + {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, + {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, + {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, + {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, + {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, + {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, + {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, + {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, + {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, + {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, + {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, ] [package.dependencies] click = ">=8.0.0" mypy-extensions = ">=0.4.3" +packaging = ">=22.0" pathspec = ">=0.9.0" platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""} +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] @@ -71,14 +85,14 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "certifi" -version = "2022.12.7" +version = "2023.5.7" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2022.12.7-py3-none-any.whl", hash = "sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18"}, - {file = "certifi-2022.12.7.tar.gz", hash = "sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3"}, + {file = "certifi-2023.5.7-py3-none-any.whl", hash = "sha256:c6c2e98f5c7869efca1f8916fed228dd91539f9f1b444c314c06eef02980c716"}, + {file = "certifi-2023.5.7.tar.gz", hash = "sha256:0f0d56dc5a6ad56fd4ba36484d6cc34451e1c6548c61daad8c320169f91eddc7"}, ] [[package]] @@ -219,14 +233,14 @@ files = [ [[package]] name = "django" -version = "3.2.18" +version = "3.2.19" description = "A high-level Python Web framework that encourages rapid development and clean, pragmatic design." category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "Django-3.2.18-py3-none-any.whl", hash = "sha256:4d492d9024c7b3dfababf49f94511ab6a58e2c9c3c7207786f1ba4eb77750706"}, - {file = "Django-3.2.18.tar.gz", hash = "sha256:08208dfe892eb64fff073ca743b3b952311104f939e7f6dae954fe72dcc533ba"}, + {file = "Django-3.2.19-py3-none-any.whl", hash = "sha256:21cc991466245d659ab79cb01204f9515690f8dae00e5eabde307f14d24d4d7d"}, + {file = "Django-3.2.19.tar.gz", hash = "sha256:031365bae96814da19c10706218c44dff3b654cc4de20a98bd2d29b9bde469f0"}, ] [package.dependencies] @@ -240,14 +254,14 @@ bcrypt = ["bcrypt"] [[package]] name = "django-auth-ldap" -version = "4.2.0" +version = "4.3.0" description = "Django LDAP authentication backend." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "django-auth-ldap-4.2.0.tar.gz", hash = "sha256:aac71e65b0a8bdcfc5cd08b70997ee3cdc37786ffd5d975b7e2cfa47595d427f"}, - {file = "django_auth_ldap-4.2.0-py3-none-any.whl", hash = "sha256:3eb0d963cd6e8225d0a588a828ce35a5c5c3309f7ad56dc5d68f8c807ddeaeff"}, + {file = "django-auth-ldap-4.3.0.tar.gz", hash = "sha256:788b5b1ee70054681d7fae7d085deaa76f2fa6f64cc9fe3dd79daef62c2f6121"}, + {file = "django_auth_ldap-4.3.0-py3-none-any.whl", hash = "sha256:6d18e747e1d9680360357945b03e0d16a3f50feea94176e2552f29ccf8c2973c"}, ] [package.dependencies] @@ -286,14 +300,14 @@ Django = ">=3.2" [[package]] name = "django-filter" -version = "22.1" +version = "23.2" description = "Django-filter is a reusable Django application for allowing users to filter querysets dynamically." category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "django-filter-22.1.tar.gz", hash = "sha256:ed473b76e84f7e83b2511bb2050c3efb36d135207d0128dfe3ae4b36e3594ba5"}, - {file = "django_filter-22.1-py3-none-any.whl", hash = "sha256:ed429e34760127e3520a67f415bec4c905d4649fbe45d0d6da37e6ff5e0287eb"}, + {file = "django-filter-23.2.tar.gz", hash = "sha256:2fe15f78108475eda525692813205fa6f9e8c1caf1ae65daa5862d403c6dbf00"}, + {file = "django_filter-23.2-py3-none-any.whl", hash = "sha256:d12d8e0fc6d3eb26641e553e5d53b191eb8cec611427d4bdce0becb1f7c172b5"}, ] [package.dependencies] @@ -315,19 +329,20 @@ pyjwkest = ">=1.3.0" [[package]] name = "django-versatileimagefield" -version = "2.2" +version = "3.0" description = "A drop-in replacement for django's ImageField that provides a flexible, intuitive and easily-extensible interface for creating new images from the one assigned to the field." category = "main" optional = false python-versions = "*" files = [ - {file = "django-versatileimagefield-2.2.tar.gz", hash = "sha256:6569d5c3e13c69ab8912ba5100084aa5abcdcffb8d1f5abc085b226e7bbd65b3"}, - {file = "django_versatileimagefield-2.2-py2.py3-none-any.whl", hash = "sha256:03766f4d2332f192978879fdb196e18c53e6ccef6c55c5c26b59747b76a97288"}, + {file = "django-versatileimagefield-3.0.tar.gz", hash = "sha256:1651db2ed36d843cfb1788f2601472a293d9ba86729369b6f6e5591112357ac7"}, + {file = "django_versatileimagefield-3.0-py2.py3-none-any.whl", hash = "sha256:19c09c2a887a1fe14eb8c72397c52aa348b315d5fdcc43bf1a1e683283750fd7"}, ] [package.dependencies] +Django = ">=3.0" Pillow = ">=2.4.0" -python-magic = ">=0.4.15,<1.0.0" +python-magic = ">=0.4.22,<1.0.0" [[package]] name = "djangorestframework" @@ -363,19 +378,19 @@ djangorestframework = ">=3.6.0" [[package]] name = "drf-spectacular" -version = "0.24.2" +version = "0.26.2" description = "Sane and flexible OpenAPI 3 schema generation for Django REST framework" category = "main" optional = false python-versions = ">=3.6" files = [ - {file = "drf-spectacular-0.24.2.tar.gz", hash = "sha256:be32417594080a52f996afd83fd47ea9c2b83cbf13f6d3fbf3de809a0dfa7ead"}, - {file = "drf_spectacular-0.24.2-py3-none-any.whl", hash = "sha256:b276e6f7bda6dfb911e742dab87c6e97bc67da2dafe82d6fd8df7cec6c8b03ec"}, + {file = "drf-spectacular-0.26.2.tar.gz", hash = "sha256:005623d6bb9de37d2d0ec24ccd59c636e4a42f9af252f1470129ac32ccab38cb"}, + {file = "drf_spectacular-0.26.2-py3-none-any.whl", hash = "sha256:e80eba58d9579bf6c3380ffd6d6a9b466c4bc35b23da0ba76dfcc96de1e907d7"}, ] [package.dependencies] Django = ">=2.2" -djangorestframework = ">=3.10" +djangorestframework = ">=3.10.3" inflection = ">=0.3.1" jsonschema = ">=2.6.0" PyYAML = ">=5.1" @@ -400,21 +415,55 @@ files = [ [package.extras] test = ["pytest (>=6)"] +[[package]] +name = "factory-boy" +version = "3.2.1" +description = "A versatile test fixtures replacement based on thoughtbot's factory_bot for Ruby." +category = "dev" +optional = false +python-versions = ">=3.6" +files = [ + {file = "factory_boy-3.2.1-py2.py3-none-any.whl", hash = "sha256:eb02a7dd1b577ef606b75a253b9818e6f9eaf996d94449c9d5ebb124f90dc795"}, + {file = "factory_boy-3.2.1.tar.gz", hash = "sha256:a98d277b0c047c75eb6e4ab8508a7f81fb03d2cb21986f627913546ef7a2a55e"}, +] + +[package.dependencies] +Faker = ">=0.7.0" + +[package.extras] +dev = ["Django", "Pillow", "SQLAlchemy", "coverage", "flake8", "isort", "mongoengine", "tox", "wheel (>=0.32.0)", "zest.releaser[recommended]"] +doc = ["Sphinx", "sphinx-rtd-theme", "sphinxcontrib-spelling"] + +[[package]] +name = "faker" +version = "18.7.0" +description = "Faker is a Python package that generates fake data for you." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "Faker-18.7.0-py3-none-any.whl", hash = "sha256:38dbc3b80e655d7301e190426ab30f04b6b7f6ca4764c5dd02772ffde0fa6dcd"}, + {file = "Faker-18.7.0.tar.gz", hash = "sha256:f02c6d3fdb5bc781f80b440cf2bdec336ed47ecfb8d620b20c3d4188ed051831"}, +] + +[package.dependencies] +python-dateutil = ">=2.4" + [[package]] name = "filelock" -version = "3.11.0" +version = "3.12.0" description = "A platform independent file lock." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "filelock-3.11.0-py3-none-any.whl", hash = "sha256:f08a52314748335c6460fc8fe40cd5638b85001225db78c2aa01c8c0db83b318"}, - {file = "filelock-3.11.0.tar.gz", hash = "sha256:3618c0da67adcc0506b015fd11ef7faf1b493f0b40d87728e19986b536890c37"}, + {file = "filelock-3.12.0-py3-none-any.whl", hash = "sha256:ad98852315c2ab702aeb628412cbf7e95b7ce8c3bf9565670b4eaecf1db370a9"}, + {file = "filelock-3.12.0.tar.gz", hash = "sha256:fc03ae43288c013d2ea83c8597001b1129db351aad9c57fe2409327916b8e718"}, ] [package.extras] -docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.2)", "diff-cover (>=7.5)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] [[package]] name = "flake8" @@ -467,14 +516,14 @@ tornado = ["tornado (>=0.2)"] [[package]] name = "identify" -version = "2.5.22" +version = "2.5.24" description = "File identification library for Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "identify-2.5.22-py2.py3-none-any.whl", hash = "sha256:f0faad595a4687053669c112004178149f6c326db71ee999ae4636685753ad2f"}, - {file = "identify-2.5.22.tar.gz", hash = "sha256:f7a93d6cf98e29bd07663c60728e7a4057615068d7a639d132dc883b2d54d31e"}, + {file = "identify-2.5.24-py2.py3-none-any.whl", hash = "sha256:986dbfb38b1140e763e413e6feb44cd731faf72d1909543178aa79b0e258265d"}, + {file = "identify-2.5.24.tar.gz", hash = "sha256:0aac67d5b4812498056d28a9a512a483f5085cc28640b02b258a59dac34301d4"}, ] [package.extras] @@ -655,14 +704,14 @@ setuptools = "*" [[package]] name = "packaging" -version = "23.0" +version = "23.1" description = "Core utilities for Python packages" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "packaging-23.0-py3-none-any.whl", hash = "sha256:714ac14496c3e68c99c29b00845f7a2b85f3bb6f1078fd9f72fd20f0570002b2"}, - {file = "packaging-23.0.tar.gz", hash = "sha256:b6ad297f8907de0fa2fe1ccbd26fdaf387f5f47c7275fedf8cce89f99446cf97"}, + {file = "packaging-23.1-py3-none-any.whl", hash = "sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61"}, + {file = "packaging-23.1.tar.gz", hash = "sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f"}, ] [[package]] @@ -759,19 +808,19 @@ tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "pa [[package]] name = "platformdirs" -version = "3.2.0" +version = "3.5.0" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "platformdirs-3.2.0-py3-none-any.whl", hash = "sha256:ebe11c0d7a805086e99506aa331612429a72ca7cd52a1f0d277dc4adc20cb10e"}, - {file = "platformdirs-3.2.0.tar.gz", hash = "sha256:d5b638ca397f25f979350ff789db335903d7ea010ab28903f57b27e1b16c2b08"}, + {file = "platformdirs-3.5.0-py3-none-any.whl", hash = "sha256:47692bc24c1958e8b0f13dd727307cff1db103fca36399f457da8e05f222fdc4"}, + {file = "platformdirs-3.5.0.tar.gz", hash = "sha256:7954a68d0ba23558d753f73437c55f89027cf8f5108c19844d4b82e5af396335"}, ] [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.22,!=1.23.4)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.2.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.3.1)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"] [[package]] name = "pluggy" @@ -791,14 +840,14 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "2.21.0" +version = "3.3.1" description = "A framework for managing and maintaining multi-language pre-commit hooks." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, - {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, + {file = "pre_commit-3.3.1-py2.py3-none-any.whl", hash = "sha256:218e9e3f7f7f3271ebc355a15598a4d3893ad9fc7b57fe446db75644543323b9"}, + {file = "pre_commit-3.3.1.tar.gz", hash = "sha256:733f78c9a056cdd169baa6cd4272d51ecfda95346ef8a89bf93712706021b907"}, ] [package.dependencies] @@ -882,30 +931,30 @@ files = [ [[package]] name = "pyasn1" -version = "0.4.8" -description = "ASN.1 types and codecs" +version = "0.5.0" +description = "Pure-Python implementation of ASN.1 types and DER/BER/CER codecs (X.208)" category = "main" optional = false -python-versions = "*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "pyasn1-0.4.8-py2.py3-none-any.whl", hash = "sha256:39c7e2ec30515947ff4e87fb6f456dfc6e84857d34be479c9d4a4ba4bf46aa5d"}, - {file = "pyasn1-0.4.8.tar.gz", hash = "sha256:aef77c9fb94a3ac588e87841208bdec464471d9871bd5050a287cc9a475cd0ba"}, + {file = "pyasn1-0.5.0-py2.py3-none-any.whl", hash = "sha256:87a2121042a1ac9358cabcaf1d07680ff97ee6404333bacca15f76aa8ad01a57"}, + {file = "pyasn1-0.5.0.tar.gz", hash = "sha256:97b7290ca68e62a832558ec3976f15cbf911bf5d7c7039d8b861c2a0ece69fde"}, ] [[package]] name = "pyasn1-modules" -version = "0.2.8" -description = "A collection of ASN.1-based protocols modules." +version = "0.3.0" +description = "A collection of ASN.1-based protocols modules" category = "main" optional = false -python-versions = "*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" files = [ - {file = "pyasn1-modules-0.2.8.tar.gz", hash = "sha256:905f84c712230b2c592c19470d3ca8d552de726050d1d1716282a1f6146be65e"}, - {file = "pyasn1_modules-0.2.8-py2.py3-none-any.whl", hash = "sha256:a50b808ffeb97cb3601dd25981f6b016cbb3d31fbf57a8b8a87428e6158d0c74"}, + {file = "pyasn1_modules-0.3.0-py2.py3-none-any.whl", hash = "sha256:d3ccd6ed470d9ffbc716be08bd90efbd44d0734bc9303818f7336070984a162d"}, + {file = "pyasn1_modules-0.3.0.tar.gz", hash = "sha256:5bd01446b736eb9d31512a30d46c1ac3395d676c6f3cafa4c03eb54b9925631c"}, ] [package.dependencies] -pyasn1 = ">=0.4.6,<0.5.0" +pyasn1 = ">=0.4.6,<0.6.0" [[package]] name = "pycodestyle" @@ -1060,18 +1109,17 @@ files = [ [[package]] name = "pytest" -version = "7.2.2" +version = "7.3.1" description = "pytest: simple powerful testing with Python" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "pytest-7.2.2-py3-none-any.whl", hash = "sha256:130328f552dcfac0b1cec75c12e3f005619dc5f874f0a06e8ff7263f0ee6225e"}, - {file = "pytest-7.2.2.tar.gz", hash = "sha256:c99ab0c73aceb050f68929bc93af19ab6db0558791c6a0715723abe9d0ade9d4"}, + {file = "pytest-7.3.1-py3-none-any.whl", hash = "sha256:3799fa815351fea3a5e96ac7e503a96fa51cc9942c3753cda7651b93c1cfa362"}, + {file = "pytest-7.3.1.tar.gz", hash = "sha256:434afafd78b1d78ed0addf160ad2b77a30d35d4bdf8af234fe621919d9ed15e3"}, ] [package.dependencies] -attrs = ">=19.2.0" colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" @@ -1080,7 +1128,7 @@ pluggy = ">=0.12,<2.0" tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] [[package]] name = "pytest-django" @@ -1101,6 +1149,24 @@ pytest = ">=5.4.0" docs = ["sphinx", "sphinx-rtd-theme"] testing = ["Django", "django-configurations (>=2.0)"] +[[package]] +name = "pytest-factoryboy" +version = "2.5.1" +description = "Factory Boy support for pytest." +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest_factoryboy-2.5.1-py3-none-any.whl", hash = "sha256:41e3465935322188daefc8720f83cebb16bf3d3a430356dc91151c55f31d99c7"}, + {file = "pytest_factoryboy-2.5.1.tar.gz", hash = "sha256:7275a52299b20c0f58b63fdf7326b3fd2b7cbefbdaa90fdcfc776bbe92197484"}, +] + +[package.dependencies] +factory_boy = ">=2.10.0" +inflection = "*" +pytest = ">=5.0.0" +typing_extensions = "*" + [[package]] name = "python-dateutil" version = "2.8.2" @@ -1145,14 +1211,14 @@ files = [ [[package]] name = "pytz" -version = "2022.7.1" +version = "2023.3" description = "World timezone definitions, modern and historical" category = "main" optional = false python-versions = "*" files = [ - {file = "pytz-2022.7.1-py2.py3-none-any.whl", hash = "sha256:78f4f37d8198e0627c5f1143240bb0206b8691d8d7ac6d78fee88b78733f8c4a"}, - {file = "pytz-2022.7.1.tar.gz", hash = "sha256:01a0681c4b9684a28304615eba55d1ab31ae00bf68ec157ec3708a8182dbbcd0"}, + {file = "pytz-2023.3-py2.py3-none-any.whl", hash = "sha256:a151b3abb88eda1d4e34a9814df37de2a80e301e68ba0fd856fb9b46bfbbbffb"}, + {file = "pytz-2023.3.tar.gz", hash = "sha256:1d8ce29db189191fb55338ee6d0387d82ab59f3d00eac103412d64e0ebd0c588"}, ] [[package]] @@ -1207,21 +1273,21 @@ files = [ [[package]] name = "requests" -version = "2.28.2" +version = "2.30.0" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=3.7, <4" +python-versions = ">=3.7" files = [ - {file = "requests-2.28.2-py3-none-any.whl", hash = "sha256:64299f4909223da747622c030b781c0d7811e359c37124b4bd368fb8c6518baa"}, - {file = "requests-2.28.2.tar.gz", hash = "sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf"}, + {file = "requests-2.30.0-py3-none-any.whl", hash = "sha256:10e94cc4f3121ee6da529d358cdaeaff2f1c409cd377dbc72b825852f2f7e294"}, + {file = "requests-2.30.0.tar.gz", hash = "sha256:239d7d4458afcb28a692cdd298d87542235f4ca8d36d03a15bfc128a6559a2f4"}, ] [package.dependencies] certifi = ">=2017.4.17" charset-normalizer = ">=2,<4" idna = ">=2.5,<4" -urllib3 = ">=1.21.1,<1.27" +urllib3 = ">=1.21.1,<3" [package.extras] socks = ["PySocks (>=1.5.6,!=1.5.7)"] @@ -1229,14 +1295,14 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "setuptools" -version = "67.6.1" +version = "67.7.2" description = "Easily download, build, install, upgrade, and uninstall Python packages" category = "main" optional = false python-versions = ">=3.7" files = [ - {file = "setuptools-67.6.1-py3-none-any.whl", hash = "sha256:e728ca814a823bf7bf60162daf9db95b93d532948c4c0bea762ce62f60189078"}, - {file = "setuptools-67.6.1.tar.gz", hash = "sha256:257de92a9d50a60b8e22abfcbb771571fde0dbf3ec234463212027a4eeecbe9a"}, + {file = "setuptools-67.7.2-py3-none-any.whl", hash = "sha256:23aaf86b85ca52ceb801d32703f12d77517b2556af839621c641fca11287952b"}, + {file = "setuptools-67.7.2.tar.gz", hash = "sha256:f104fa03692a2602fa0fec6c6a9e63b6c8a968de13e17c026957dd1f53d80990"}, ] [package.extras] @@ -1258,16 +1324,21 @@ files = [ [[package]] name = "sqlparse" -version = "0.4.3" +version = "0.4.4" description = "A non-validating SQL parser." category = "main" optional = false python-versions = ">=3.5" files = [ - {file = "sqlparse-0.4.3-py3-none-any.whl", hash = "sha256:0323c0ec29cd52bceabc1b4d9d579e311f3e4961b98d174201d5622a23b85e34"}, - {file = "sqlparse-0.4.3.tar.gz", hash = "sha256:69ca804846bb114d2ec380e4360a8a340db83f0ccf3afceeb1404df028f57268"}, + {file = "sqlparse-0.4.4-py3-none-any.whl", hash = "sha256:5430a4fe2ac7d0f93e66f1efc6e1338a41884b7ddf2a350cedd20ccc4d9d28f3"}, + {file = "sqlparse-0.4.4.tar.gz", hash = "sha256:d446183e84b8349fa3061f0fe7f06ca94ba65b426946ffebe6e3e8295332420c"}, ] +[package.extras] +dev = ["build", "flake8"] +doc = ["sphinx"] +test = ["pytest", "pytest-cov"] + [[package]] name = "tomli" version = "2.0.1" @@ -1280,6 +1351,18 @@ files = [ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] +[[package]] +name = "typing-extensions" +version = "4.5.0" +description = "Backported and Experimental Type Hints for Python 3.7+" +category = "dev" +optional = false +python-versions = ">=3.7" +files = [ + {file = "typing_extensions-4.5.0-py3-none-any.whl", hash = "sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4"}, + {file = "typing_extensions-4.5.0.tar.gz", hash = "sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb"}, +] + [[package]] name = "uritemplate" version = "4.1.1" @@ -1294,61 +1377,62 @@ files = [ [[package]] name = "urllib3" -version = "1.26.15" +version = "2.0.2" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=3.7" files = [ - {file = "urllib3-1.26.15-py2.py3-none-any.whl", hash = "sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"}, - {file = "urllib3-1.26.15.tar.gz", hash = "sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305"}, + {file = "urllib3-2.0.2-py3-none-any.whl", hash = "sha256:d055c2f9d38dc53c808f6fdc8eab7360b6fdbbde02340ed25cfbcd817c62469e"}, + {file = "urllib3-2.0.2.tar.gz", hash = "sha256:61717a1095d7e155cdb737ac7bb2f4324a858a1e2e6466f6d03ff630ca68d3cc"}, ] [package.extras] -brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] -socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.21.0" +version = "20.23.0" description = "Virtual Python Environment builder" category = "dev" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.21.0-py3-none-any.whl", hash = "sha256:31712f8f2a17bd06234fa97fdf19609e789dd4e3e4bf108c3da71d710651adbc"}, - {file = "virtualenv-20.21.0.tar.gz", hash = "sha256:f50e3e60f990a0757c9b68333c9fdaa72d7188caa417f96af9e52407831a3b68"}, + {file = "virtualenv-20.23.0-py3-none-any.whl", hash = "sha256:6abec7670e5802a528357fdc75b26b9f57d5d92f29c5462ba0fbe45feacc685e"}, + {file = "virtualenv-20.23.0.tar.gz", hash = "sha256:a85caa554ced0c0afbd0d638e7e2d7b5f92d23478d05d17a76daeac8f279f924"}, ] [package.dependencies] distlib = ">=0.3.6,<1" -filelock = ">=3.4.1,<4" -platformdirs = ">=2.4,<4" +filelock = ">=3.11,<4" +platformdirs = ">=3.2,<4" [package.extras] -docs = ["furo (>=2022.12.7)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] -test = ["covdefaults (>=2.2.2)", "coverage (>=7.1)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23)", "pytest (>=7.2.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2023.3.27)", "proselint (>=0.13)", "sphinx (>=6.1.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=22.12)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.3)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.3.1)", "pytest-env (>=0.8.1)", "pytest-freezegun (>=0.4.2)", "pytest-mock (>=3.10)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=67.7.1)", "time-machine (>=2.9)"] [[package]] name = "werkzeug" -version = "2.2.3" +version = "2.3.3" description = "The comprehensive WSGI web application library." category = "dev" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "Werkzeug-2.2.3-py3-none-any.whl", hash = "sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612"}, - {file = "Werkzeug-2.2.3.tar.gz", hash = "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe"}, + {file = "Werkzeug-2.3.3-py3-none-any.whl", hash = "sha256:4866679a0722de00796a74086238bb3b98d90f423f05de039abb09315487254a"}, + {file = "Werkzeug-2.3.3.tar.gz", hash = "sha256:a987caf1092edc7523edb139edb20c70571c4a8d5eed02e0b547b4739174d091"}, ] [package.dependencies] MarkupSafe = ">=2.1.1" [package.extras] -watchdog = ["watchdog"] +watchdog = ["watchdog (>=2.3)"] [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "f22518a9d8fc35ac7dceb3bc7d75292dcb16411a3ce150d26934b2b95b272a14" +content-hash = "e3b4e1e8877abd983a3ffd4c7c1280cd8d1241f7675eb05be4071e965644d8b1" diff --git a/program/tests/factories.py b/program/tests/factories.py new file mode 100644 index 00000000..d0987c86 --- /dev/null +++ b/program/tests/factories.py @@ -0,0 +1,83 @@ +from datetime import time, timedelta + +import factory + +from django.contrib.auth.models import User +from django.utils.timezone import now +from program.models import ( + FundingCategory, + Host, + Image, + RRule, + Schedule, + Show, + TimeSlot, + Type, + UserProfile, +) + + +class CommonUserFactory(factory.django.DjangoModelFactory): + class Meta: + model = User + + password = "password" + username = factory.Sequence(lambda n: "common_%d" % n) + + +class HostFactory(factory.django.DjangoModelFactory): + class Meta: + model = Host + + name = factory.Sequence(lambda n: "host %d" % n) + + +class ImageFactory(factory.django.DjangoModelFactory): + class Meta: + model = Image + + +class FundingCategoryFactory(factory.django.DjangoModelFactory): + class Meta: + model = FundingCategory + + name = factory.Sequence(lambda n: "funding category %d" % n) + slug = factory.Sequence(lambda n: "fc_%d" % n) + + +class TypeFactory(factory.django.DjangoModelFactory): + class Meta: + model = Type + + name = factory.Sequence(lambda n: "type %d" % n) + slug = factory.Sequence(lambda n: "t_%d" % n) + + +class ShowFactory(factory.django.DjangoModelFactory): + class Meta: + model = Show + + name = factory.Sequence(lambda n: "show %d" % n) + slug = factory.Sequence(lambda n: "%s_d" % n) + + +class RRuleFactory(factory.django.DjangoModelFactory): + class Meta: + model = RRule + + +class ScheduleFactory(factory.django.DjangoModelFactory): + class Meta: + model = Schedule + + end_time = "03:00:00" + first_date = "2023-01-01" + start_time = "02:00:00" + + +class TimeslotFactory(factory.django.DjangoModelFactory): + class Meta: + model = TimeSlot + + end = now() + timedelta(hours=1) + start = now() diff --git a/program/tests/test_schedules.py b/program/tests/test_schedules.py new file mode 100644 index 00000000..32dabb5c --- /dev/null +++ b/program/tests/test_schedules.py @@ -0,0 +1,220 @@ +from datetime import datetime, timedelta + +import pytest + +from conftest import assert_data +from program.models import TimeSlot +from program.tests.factories import RRuleFactory, ScheduleFactory + +pytestmark = pytest.mark.django_db + + +def url(show=None, schedule=None) -> str: + if show and schedule: + return f"/api/v1/shows/{show.id}/schedules/{schedule.id}/" + elif show and not schedule: + return f"/api/v1/shows/{show.id}/schedules/" + elif not show and schedule: + return f"/api/v1/schedules/{schedule.id}/" + else: + return f"/api/v1/schedules/" + + +def schedule_data(rrule) -> dict[str, dict[str | int]]: + now = datetime.now() + in_an_hour = now + timedelta(hours=1) + in_a_year = now + timedelta(days=365) + + return { + "schedule": { + "end_time": in_an_hour.strftime("%H:%M:%S"), + "first_date": now.strftime("%Y-%m-%d"), + "last_date": in_a_year.strftime("%Y-%m-%d"), + "rrule": rrule.id, + "start_time": now.strftime("%H:%M:%S"), + }, + } + + +def test_create_once_schedule(admin_api_client, once_rrule, show): + data = schedule_data(once_rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 1 + + assert_data(response, data) + + +def test_create_daily_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=3) + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 365 or 366 + + assert_data(response, data) + + +def test_create_business_days_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=2, by_weekdays="0,1,2,3,4") + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 261 or 262 + + assert_data(response, data) + + +def test_create_weekends_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=2, by_weekdays="5,6") + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 104 or 105 + + assert_data(response, data) + + +def test_create_weekly_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=2) + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 52 or 53 + + assert_data(response, data) + + +def test_create_2weekly_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=2, interval=2) + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 26 or 27 + + assert_data(response, data) + + +def test_create_4weekly_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=2, interval=4) + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 13 or 14 + + assert_data(response, data) + + +def test_create_monthly_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=1) + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 12 + + assert_data(response, data) + + +def test_create_2monthly_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=1, interval=2) + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 6 + + assert_data(response, data) + + +def test_create_3monthly_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=1, interval=3) + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 4 + + assert_data(response, data) + + +def test_create_4monthly_schedule(admin_api_client, show): + rrule = RRuleFactory(freq=1, interval=4) + data = schedule_data(rrule) + + response = admin_api_client.post(url(show=show), data=data, format="json") + + assert response.status_code == 201 + assert TimeSlot.objects.all().count() == 3 + + assert_data(response, data) + + +def test_create_schedule_forbidden_for_common_user(common_api_client1, once_rrule, show): + data = schedule_data(once_rrule) + + response = common_api_client1.post(url(show=show), data=data, format="json") + + assert response.status_code == 403 + + +def test_delete_schedule(admin_api_client, once_schedule): + response = admin_api_client.delete(url(schedule=once_schedule)) + + assert response.status_code == 204 + + +def test_delete_schedule_forbidden_for_common_user(common_api_client1, once_schedule): + response = common_api_client1.delete(url(schedule=once_schedule)) + + assert response.status_code == 403 + + +def test_list_schedules(api_client, once_rrule, show): + SCHEDULES = 3 + ScheduleFactory.create_batch(size=SCHEDULES, show=show, rrule=once_rrule) + + response = api_client.get(url(show=show)) + + assert response.status_code == 200 + assert len(response.data) == 3 + + +def test_retrieve_schedule(api_client, once_schedule): + response = api_client.get(url(schedule=once_schedule)) + + assert response.status_code == 200 + + +def test_update_schedule(admin_api_client, once_schedule): + update = { + "schedule": { + "first_date": once_schedule.first_date, + "start_time": once_schedule.start_time, + "end_time": once_schedule.end_time, + "rrule": once_schedule.rrule.id, + }, + } + + response = admin_api_client.put(url(schedule=once_schedule), data=update, format="json") + + assert response.status_code == 200 + + assert_data(response, update) diff --git a/program/tests/test_shows.py b/program/tests/test_shows.py new file mode 100644 index 00000000..3f997fd0 --- /dev/null +++ b/program/tests/test_shows.py @@ -0,0 +1,86 @@ +import pytest + +from conftest import assert_data +from program.tests.factories import ShowFactory + +pytestmark = pytest.mark.django_db + + +def url(show=None) -> str: + return f"/api/v1/shows/{show.id}/" if show else "/api/v1/shows/" + + +def show_data(funding_category, type_) -> dict[str, str | int]: + return { + "funding_category": funding_category.id, + "name": "NAME", + "short_description": "SHORT DESCRIPTION", + "slug": "SLUG", + "type": type_.id, + } + + +def test_create_show(admin_api_client, funding_category, type_): + data = show_data(funding_category, type_) + + response = admin_api_client.post(url(), data=data) + + assert response.status_code == 201 + + assert_data(response, data) + + +def test_create_show_forbidden_for_common_user(common_api_client1, funding_category, type_): + data = show_data(funding_category, type_) + + response = common_api_client1.post(url(), data=data) + + assert response.status_code == 403 + + +def test_delete_show(admin_api_client, show): + response = admin_api_client.delete(url(show)) + + assert response.status_code == 204 + + +def test_delete_show_forbidden_for_common_user(common_api_client1, show): + response = common_api_client1.delete(url(show)) + + assert response.status_code == 403 + + +def test_list_shows(api_client): + SHOWS = 3 + ShowFactory.create_batch(size=SHOWS) + + response = api_client.get(url()) + + assert response.status_code == 200 + assert len(response.data) == SHOWS + + +def test_retrieve_show_as_admin_user(admin_api_client, show): + response = admin_api_client.get(url(show)) + + assert response.status_code == 200 + assert response.data["id"] == show.id + assert "internal_note" in response.data + + +def test_update_show(admin_api_client, funding_category, type_, show): + update = show_data(funding_category, type_) + + response = admin_api_client.put(url(show), data=update) + + assert response.status_code == 200 + + assert_data(response, update) + + +def test_update_show_forbidden_for_common_user(common_api_client1, funding_category, type_, show): + update = show_data(funding_category, type_) + + response = common_api_client1.put(url(show), data=update) + + assert response.status_code == 403 diff --git a/program/tests/test_timeslots.py b/program/tests/test_timeslots.py new file mode 100644 index 00000000..51489899 --- /dev/null +++ b/program/tests/test_timeslots.py @@ -0,0 +1,95 @@ +import pytest + +pytestmark = pytest.mark.django_db + + +def url(show=None, schedule=None, timeslot=None) -> str: + if show and schedule and timeslot: + return f"/api/v1/shows/{show.id}/schedules/{schedule.id}/timeslots/{timeslot.id}/" + elif show and schedule: + return f"/api/v1/shows/{show.id}/schedules/{schedule.id}/timeslots/" + elif show: + return f"/api/v1/shows/{show.id}/schedules/" + elif timeslot: + return f"/api/v1/timeslots/{timeslot.id}/" + else: + return "/api/v1/timeslots/" + + +def timeslot_data() -> dict[str, str | int]: + return { + "memo": "MEMO", + "playlist_id": 1, + "repetition_of": 1, + } + + +def test_delete_timeslot_as_admin(admin_api_client, once_timeslot): + response = admin_api_client.delete(url(timeslot=once_timeslot)) + + assert response.status_code == 204 + + +def test_delete_forbidden_as_common_user(common_api_client1, once_timeslot): + response = common_api_client1.delete(url(timeslot=once_timeslot)) + + assert response.status_code == 403 + + +def test_delete_forbidden_as_unauthenticated_user(api_client, once_timeslot): + response = api_client.delete(url(timeslot=once_timeslot)) + + assert response.status_code == 403 + + +def test_retrieve_timeslot(api_client, once_timeslot): + response = api_client.get(url(timeslot=once_timeslot)) + + assert response.status_code == 200 + + +def test_update_memo_as_admin(admin_api_client, once_timeslot): + update = {"memo": "MEMO"} + + response = admin_api_client.patch(url(timeslot=once_timeslot), data=update) + + assert response.status_code == 200 + + +def test_update_playlist_id_as_admin(admin_api_client, once_timeslot): + update = {"playlist_id": 1} + + response = admin_api_client.patch(url(timeslot=once_timeslot), data=update) + + assert response.status_code == 200 + + +def test_update_repetition_of_as_admin(admin_api_client, once_timeslot): + update = {"repetition_of": 1} + response = admin_api_client.patch(url(timeslot=once_timeslot), data=update) + + assert response.status_code == 200 + + +def test_update_as_admin(admin_api_client, once_timeslot): + update = timeslot_data() + + response = admin_api_client.put(url(timeslot=once_timeslot), data=update) + + assert response.status_code == 200 + + +def test_update_forbidden_as_not_owner(common_api_client2, owned_show_once_timeslot): + update = timeslot_data() + + response = common_api_client2.put(url(timeslot=owned_show_once_timeslot), data=update) + + assert response.status_code == 403 + + +def test_update_timeslot_forbidden_as_unauthenticated(api_client, once_timeslot): + update = timeslot_data() + + response = api_client.put(url(timeslot=once_timeslot), data=update) + + assert response.status_code == 403 diff --git a/program/tests/test_users.py b/program/tests/test_users.py new file mode 100644 index 00000000..d31439d3 --- /dev/null +++ b/program/tests/test_users.py @@ -0,0 +1,162 @@ +import pytest + +from conftest import assert_data +from program.tests.factories import CommonUserFactory + +pytestmark = pytest.mark.django_db + + +def url(user=None) -> str: + return f"/api/v1/users/{user.id}/" if user else "/api/v1/users/" + + +def user_data(is_superuser=False, add_profile=False) -> dict[str, str | dict[str, str]]: + data = { + "password": "password", + "username": "user", + } + + if is_superuser: + data["is_superuser"] = is_superuser + + if add_profile: + data["profile"] = { + "cba_username": "CBA USERNAME", + "cba_user_token": "CBA USER TOKEN", + } + + return data + + +def test_create_user(admin_api_client): + data = user_data() + + response = admin_api_client.post(url(), data=data) + + assert response.status_code == 201 + + assert_data(response, data) + + +def test_create_superuser(admin_api_client): + data = user_data(is_superuser=True) + + response = admin_api_client.post(url(), data=data) + + assert response.status_code == 201 + + assert_data(response, data) + + +def test_create_user_unauthorized(common_api_client1): + data = user_data() + + response = common_api_client1.post(url(), data=data) + + assert response.status_code == 403 + + +def test_list_users_as_common_user(common_user1, common_api_client1): + USERS = 3 + CommonUserFactory.create_batch(size=USERS) + + response = common_api_client1.get(url()) + + assert response.status_code == 200 + assert len(response.data) == 1 + assert response.data[0]["username"] == common_user1.username + + +def test_list_users_as_other_common_user(common_user1, common_user2, common_api_client2): + USERS = 3 + CommonUserFactory.create_batch(size=USERS) + + response = common_api_client2.get(url()) + + assert response.status_code == 200 + assert len(response.data) == 1 + assert response.data[0]["username"] == common_user2.username + + +def test_list_users_as_superuser(admin_api_client): + USERS = 3 + CommonUserFactory.create_batch(size=USERS) + + response = admin_api_client.get(url()) + + assert response.status_code == 200 + assert len(response.data) == USERS + 1 + + +def test_list_users_unauthenticated(api_client): + USERS = 3 + CommonUserFactory.create_batch(size=USERS) + + response = api_client.get(url()) + + assert response.status_code == 200 + assert len(response.data) == 0 + + +def test_retrieve_user_as_common_user(common_user1, common_api_client1): + response = common_api_client1.get(url(common_user1)) + + assert response.status_code == 200 + assert response.data["username"] == common_user1.username + + +def test_retrieve_user_not_found_as_other_common_user(common_user1, common_api_client2): + response = common_api_client2.get(url(common_user1)) + + assert response.status_code == 404 + + +def test_retrieve_user_as_superuser(common_user1, admin_api_client): + response = admin_api_client.get(url(common_user1)) + + assert response.status_code == 200 + assert response.data["username"] == common_user1.username + + +def test_retrieve_user_not_found_unauthenticated(common_user1, api_client): + response = api_client.get(url(common_user1)) + + assert response.status_code == 404 + + +def test_update_user(common_user1, admin_api_client): + update = { + "email": "user@aura.radio", + "first_name": "FIRST NAME", + "last_name": "LAST NAME", + } + + response = admin_api_client.patch(url(common_user1), data=update) + + assert response.status_code == 200 + + assert_data(response, update) + + +def test_update_user_forbidden_as_common_user(common_user1, common_api_client1): + update = {"username": "USERNAME"} + + response = common_api_client1.patch(url(common_user1), data=update) + + assert response.status_code == 403 + + +def test_update_user_forbidden_as_other_common_user(common_user1, common_api_client2): + update = {"username": "USERNAME"} + + response = common_api_client2.patch(url(common_user1), data=update) + + assert response.status_code == 403 + + +def test_update_user_forbidden_unauthenticated(common_user1, api_client): + update = {"username": "USERNAME"} + + response = api_client.patch(url(common_user1), data=update) + + assert response.status_code == 403 diff --git a/pyproject.toml b/pyproject.toml index 3fdf11cc..7937bbc0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -44,6 +44,16 @@ werkzeug = "^2.2.3" [tool.poetry.group.test.dependencies] pytest = "^7.1.3" pytest-django = "^4.5.2" +pytest-factoryboy = "^2.5.1" + +[tool.pytest.ini_options] +DJANGO_SETTINGS_MODULE = "steering.settings" +django_debug_mode = true +filterwarnings = [ + "ignore::DeprecationWarning", + "ignore::django.utils.deprecation.RemovedInDjango40Warning", + "ignore::django.utils.deprecation.RemovedInDjango41Warning" +] [tool.black] line-length = 99 -- GitLab