From 0bda16de6dae7a684acf4332312765fe2d78741c Mon Sep 17 00:00:00 2001 From: rubenwardy Date: Sun, 19 Jan 2020 19:09:04 +0000 Subject: [PATCH] Add API tests --- .gitlab-ci.yml | 2 +- .pylintrc | 1 - app/default_data.py | 16 +++++- app/models.py | 6 +-- app/tests/test_api.py | 105 +++++++++++++++++++++++++++++++++++++ app/tests/test_homepage.py | 6 +-- app/tests/utils.py | 17 +++++- utils/setup.py | 5 +- utils/tests.sh | 2 +- utils/tests_cov.sh | 3 ++ 10 files changed, 149 insertions(+), 14 deletions(-) delete mode 100644 .pylintrc create mode 100644 app/tests/test_api.py create mode 100755 utils/tests_cov.sh diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index c0d85bc2..6381efe3 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -18,5 +18,5 @@ UI_Test: - cp utils/gitlabci/* . - docker-compose up -d - ./utils/run_migrations.sh - - ./utils/tests.sh + - ./utils/tests_cov.sh - docker-compose down diff --git a/.pylintrc b/.pylintrc deleted file mode 100644 index d629e713..00000000 --- a/.pylintrc +++ /dev/null @@ -1 +0,0 @@ -ignored-classes=SQLObject,Registrant,scoped_session diff --git a/app/default_data.py b/app/default_data.py index 6c0fdad2..85f42b32 100644 --- a/app/default_data.py +++ b/app/default_data.py @@ -11,6 +11,11 @@ def populate(session): admin_user.rank = UserRank.ADMIN session.add(admin_user) + session.add(MinetestRelease("None", 0)) + session.add(MinetestRelease("0.4.16/17", 32)) + session.add(MinetestRelease("5.0", 37)) + session.add(MinetestRelease("5.1", 38)) + tags = {} for tag in ["Inventory", "Mapgen", "Building", \ "Mobs and NPCs", "Tools", "Player effects", \ @@ -34,7 +39,14 @@ def populate(session): session.add(row) -def populate_test_data(session, licenses, tags, admin_user): +def populate_test_data(session): + licenses = { x.name : x for x in License.query.all() } + tags = { x.name : x for x in Tag.query.all() } + admin_user = User.query.filter_by(rank=UserRank.ADMIN).first() + v4 = MinetestRelease.query.filter_by(protocol=32).first() + v50 = MinetestRelease.query.filter_by(protocol=37).first() + v51 = MinetestRelease.query.filter_by(protocol=38).first() + ez = User("Shara") ez.github_username = "Ezhh" ez.forums_username = "Shara" @@ -105,6 +117,7 @@ awards.register_achievement("award_mesefind",{ rel = PackageRelease() rel.package = mod1 + rel.min_rel = v51 rel.title = "v1.0.0" rel.url = "https://github.com/rubenwardy/awards/archive/master.zip" rel.approved = True @@ -218,6 +231,7 @@ No warranty is provided, express or implied, for any part of the project. rel = PackageRelease() rel.package = mod rel.title = "v1.0.0" + rel.max_rel = v4 rel.url = "https://github.com/ezhh/handholds/archive/master.zip" rel.approved = True session.add(rel) diff --git a/app/models.py b/app/models.py index 61e92223..1ff2904d 100644 --- a/app/models.py +++ b/app/models.py @@ -472,8 +472,7 @@ class Package(db.Model): "short_description": self.short_desc, "type": self.type.toName(), "release": release and release.id, - "thumbnail": (base_url + tnurl) if tnurl is not None else None, - "score": round(self.score * 10) / 10 + "thumbnail": (base_url + tnurl) if tnurl is not None else None } def getAsDictionary(self, base_url, version=None, protonum=None): @@ -708,8 +707,9 @@ class MinetestRelease(db.Model): name = db.Column(db.String(100), unique=True, nullable=False) protocol = db.Column(db.Integer, nullable=False, default=0) - def __init__(self, name=None): + def __init__(self, name=None, protocol=0): self.name = name + self.protocol = protocol def getActual(self): return None if self.name == "None" else self diff --git a/app/tests/test_api.py b/app/tests/test_api.py new file mode 100644 index 00000000..80096560 --- /dev/null +++ b/app/tests/test_api.py @@ -0,0 +1,105 @@ +import pytest +from app import app +from app.default_data import populate_test_data +from app.models import db, License, Tag, User, UserRank, Package +from utils import client, recreate_db, parse_json +from utils import is_str, is_int, is_optional + +def validate_package_list(packages, strict=False): + valid_keys = { + "author", "name", "release", + "short_description", "thumbnail", + "title", "type" + } + + for package in packages: + assert set(package.keys()).issubset(valid_keys) + + assert is_str(package.get("author")) + assert is_str(package.get("name")) + if strict: + assert is_int(package.get("release")) + else: + assert is_optional(int, package.get("release")) + assert is_str(package.get("short_description")) + assert is_optional(str, package.get("thumbnail")) + assert is_str(package.get("title")) + assert is_str(package.get("type")) + + +def test_packages_empty(client): + """Start with a blank database.""" + + rv = client.get("/api/packages/") + assert parse_json(rv.data) == [] + + +def test_packages_with_contents(client): + """Start with a test database.""" + + + populate_test_data(db.session) + db.session.commit() + + rv = client.get("/api/packages/") + + packages = parse_json(rv.data) + + assert len(packages) > 0 + assert len(packages) == Package.query.filter_by(approved=True).count() + + validate_package_list(packages) + + +def test_packages_with_query(client): + """Start with a test database.""" + + populate_test_data(db.session) + db.session.commit() + + rv = client.get("/api/packages/?q=food") + + packages = parse_json(rv.data) + + assert len(packages) == 2 + + validate_package_list(packages) + + assert (packages[0]["name"] == "food" and packages[1]["name"] == "food_sweet") or \ + (packages[1]["name"] == "food" and packages[0]["name"] == "food_sweet") + + +def test_packages_with_protocol_high(client): + """Start with a test database.""" + + populate_test_data(db.session) + db.session.commit() + + rv = client.get("/api/packages/?protocol_version=40") + + packages = parse_json(rv.data) + + assert len(packages) == 4 + + for package in packages: + assert package["name"] != "mesecons" + + validate_package_list(packages, True) + + +def test_packages_with_protocol_low(client): + """Start with a test database.""" + + populate_test_data(db.session) + db.session.commit() + + rv = client.get("/api/packages/?protocol_version=20") + + packages = parse_json(rv.data) + + assert len(packages) == 4 + + for package in packages: + assert package["name"] != "awards" + + validate_package_list(packages, True) diff --git a/app/tests/test_homepage.py b/app/tests/test_homepage.py index 2bfdbca1..1636b6da 100644 --- a/app/tests/test_homepage.py +++ b/app/tests/test_homepage.py @@ -14,11 +14,7 @@ def test_homepage_empty(client): def test_homepage_with_contents(client): """Start with a test database.""" - licenses = { x.name : x for x in License.query.all() } - tags = { x.name : x for x in Tag.query.all() } - admin_user = User.query.filter_by(rank=UserRank.ADMIN).first() - - populate_test_data(db.session, licenses, tags, admin_user) + populate_test_data(db.session) db.session.commit() rv = client.get("/") diff --git a/app/tests/utils.py b/app/tests/utils.py index 782bb1de..be2b8690 100644 --- a/app/tests/utils.py +++ b/app/tests/utils.py @@ -1,4 +1,4 @@ -import pytest +import pytest, json from app import app from app.models import db, User from app.default_data import populate @@ -16,6 +16,21 @@ def recreate_db(): populate(db.session) db.session.commit() +def parse_json(b): + return json.loads(b.decode("utf8")) + +def is_type(t, v): + return v and isinstance(v, t) + +def is_optional(t, v): + return not v or isinstance(v, t) + +def is_str(v): + return is_type(str, v) + +def is_int(v): + return is_type(int, v) + @pytest.fixture def client(): diff --git a/utils/setup.py b/utils/setup.py index fb87fcc6..1ac9bf33 100644 --- a/utils/setup.py +++ b/utils/setup.py @@ -40,6 +40,9 @@ if create_db: db.create_all() print("Filling database...") + populate(db.session) if test_data: - populate_test_data(licenses, tags, User.filter_by(rank=UserRank.ADMIN).first()) + populate_test_data(db.session) + +db.session.commit() diff --git a/utils/tests.sh b/utils/tests.sh index 82df3d15..2330a234 100755 --- a/utils/tests.sh +++ b/utils/tests.sh @@ -1,3 +1,3 @@ #!/bin/sh -docker exec contentdb_app_1 sh -c "FLASK_CONFIG=../config.cfg FLASK_APP=app/__init__.py python -m pytest app/tests/ --cov=app --disable-warnings" +docker exec contentdb_app_1 sh -c "FLASK_CONFIG=../config.cfg FLASK_APP=app/__init__.py python -m pytest app/tests/ --disable-warnings" diff --git a/utils/tests_cov.sh b/utils/tests_cov.sh new file mode 100755 index 00000000..82df3d15 --- /dev/null +++ b/utils/tests_cov.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +docker exec contentdb_app_1 sh -c "FLASK_CONFIG=../config.cfg FLASK_APP=app/__init__.py python -m pytest app/tests/ --cov=app --disable-warnings"