Repository :
http://git.fedorahosted.org/cgit/copr.git
On branch : master
---------------------------------------------------------------
commit e768f7e720fd16a44e792164509f94d514ec2e59
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Wed Sep 9 15:27:57 2015 +0200
[frontend][API] Added query parameter `is_finished` to the Builds collection; fixed
parsing of the boolean query args
---------------------------------------------------------------
.../coprs/rest_api/resources/build.py | 7 +-
.../coprs/rest_api/resources/mock_chroot.py | 4 +-
.../coprs/rest_api/resources/project.py | 6 +-
.../coprs/rest_api/resources/project_chroot.py | 3 -
frontend/coprs_frontend/coprs/rest_api/util.py | 21 +++++-
frontend/coprs_frontend/tests/coprs_test_case.py | 7 ++-
.../coprs_frontend/tests/test_api/test_build_r.py | 76 +++++++++++++-------
.../tests/test_api/test_build_task_r.py | 78 +++++++++++++++++++-
8 files changed, 161 insertions(+), 41 deletions(-)
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/build.py
b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
index bc1605f..082bb25 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/build.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
@@ -12,7 +12,7 @@ from ..common import get_project_safe
from ..exceptions import MalformedRequest, CannotProcessRequest, AccessForbidden
from ..common import render_build, rest_api_auth_required, render_build_task,
get_build_safe, get_user_safe
from ..schemas import BuildSchema, BuildCreateSchema, BuildCreateFromUrlSchema
-from ..util import mm_deserialize, get_request_parser
+from ..util import mm_deserialize, get_request_parser, arg_bool
class BuildListR(Resource):
@@ -27,7 +27,7 @@ class BuildListR(Resource):
parser.add_argument('limit', type=int)
parser.add_argument('offset', type=int)
- parser.add_argument('is_finished', type=bool)
+ parser.add_argument('is_finished', type=arg_bool)
# parser.add_argument('package', type=str)
req_args = parser.parse_args()
@@ -44,7 +44,6 @@ class BuildListR(Resource):
if req_args["is_finished"] is not None:
is_finished = req_args["is_finished"]
query = BuildsLogic.filter_is_finished(query, is_finished)
- # TODO: add test!
if req_args["limit"] is not None:
limit = req_args["limit"]
@@ -161,7 +160,7 @@ class BuildR(Resource):
def get(self, build_id):
parser = get_request_parser()
- parser.add_argument('show_build_tasks', type=bool, default=False)
+ parser.add_argument('show_build_tasks', type=arg_bool, default=False)
req_args = parser.parse_args()
build = get_build_safe(build_id)
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/mock_chroot.py
b/frontend/coprs_frontend/coprs/rest_api/resources/mock_chroot.py
index a81569c..262e57f 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/mock_chroot.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/mock_chroot.py
@@ -6,7 +6,7 @@ from flask_restful import Resource, reqparse
from ...logic.coprs_logic import MockChrootsLogic
from ..schemas import MockChrootSchema
-from ..util import get_one_safe, get_request_parser
+from ..util import get_one_safe, get_request_parser, arg_bool
def render_mock_chroot(chroot):
@@ -22,7 +22,7 @@ class MockChrootListR(Resource):
def get(self):
parser = get_request_parser()
- parser.add_argument('active_only', type=bool)
+ parser.add_argument('active_only', type=arg_bool)
req_args = parser.parse_args()
active_only = False
if req_args["active_only"]:
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/project.py
b/frontend/coprs_frontend/coprs/rest_api/resources/project.py
index e3157b8..a9a84f0 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/project.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/project.py
@@ -16,7 +16,7 @@ from ...exceptions import DuplicateException
from ..common import rest_api_auth_required, render_copr_chroot, render_build,
render_project, get_project_safe
from ..schemas import ProjectSchema, ProjectCreateSchema
from ..exceptions import ObjectAlreadyExists, CannotProcessRequest, AccessForbidden
-from ..util import mm_deserialize, get_request_parser
+from ..util import mm_deserialize, get_request_parser, arg_bool
log = getLogger(__name__)
@@ -111,8 +111,8 @@ class ProjectR(Resource):
def get(self, project_id):
parser = get_request_parser()
- parser.add_argument('show_builds', type=bool, default=False)
- parser.add_argument('show_chroots', type=bool, default=False)
+ parser.add_argument('show_builds', type=arg_bool, default=False)
+ parser.add_argument('show_chroots', type=arg_bool, default=False)
req_args = parser.parse_args()
project = get_project_safe(project_id)
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/project_chroot.py
b/frontend/coprs_frontend/coprs/rest_api/resources/project_chroot.py
index ff7a3b1..dfefbcf 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/project_chroot.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/project_chroot.py
@@ -60,9 +60,6 @@ class ProjectChrootListR(Resource):
if get_one_safe(CoprChrootsLogic.get_by_name(project, name)) is not None:
raise ObjectAlreadyExists("Copr {} already has chroot {}
enabled"
.format(project.full_name, name))
- else:
- raise ServerError("Unexpected error, contact site administrator:
{}"
- .format(err))
resp = make_response("", 201)
resp.headers["Location"] = url_for(".projectchrootr",
diff --git a/frontend/coprs_frontend/coprs/rest_api/util.py
b/frontend/coprs_frontend/coprs/rest_api/util.py
index 402edd1..ef5a3e7 100644
--- a/frontend/coprs_frontend/coprs/rest_api/util.py
+++ b/frontend/coprs_frontend/coprs/rest_api/util.py
@@ -82,4 +82,23 @@ class MyArg(Argument):
def get_request_parser():
return RequestParser(argument_class=MyArg)
- #return RequestParser(bundle_errors=True)
+
+
+def arg_bool(value):
+ """
+ :param str value: value to convert
+ :rtype: bool
+ :raises ValueError:
+ """
+ true_values = ["true", "yes", "1"]
+ false_values = ["false", "no", "0"]
+ value = str(value).strip().lower()
+
+ if value in true_values:
+ return True
+ elif value in false_values:
+ return False
+
+ raise ValueError("Value `{}` doesn't belong to either true of false sets.
"
+ "Allowed values: {} and {}"
+ .format(value, true_values, false_values))
diff --git a/frontend/coprs_frontend/tests/coprs_test_case.py
b/frontend/coprs_frontend/tests/coprs_test_case.py
index a6dff96..6da78d1 100644
--- a/frontend/coprs_frontend/tests/coprs_test_case.py
+++ b/frontend/coprs_frontend/tests/coprs_test_case.py
@@ -218,6 +218,7 @@ class CoprsTestCase(object):
[self.b1, self.b2, self.b3, self.b4],
[self.b1_bc, self.b2_bc, self.b3_bc, self.b4_bc]):
+ # import ipdb; ipdb.set_trace()
status = None
if build is self.b1: # this build is going to be deleted
status = StatusEnum("succeeded")
@@ -229,11 +230,12 @@ class CoprsTestCase(object):
git_hash="12345",
)
- if build is [self.b1, self.b2]:
+ if build is self.b1 or build is self.b2:
buildchroot.started_on = 139086644000
buildchroot.ended_on = 149086644000
build.ended_on = 149086644000
+
build_chroots.append(buildchroot)
self.db.session.add(buildchroot)
@@ -275,6 +277,9 @@ class CoprsTestCase(object):
@pytest.fixture
def f_build_many_chroots(self):
+ """
+ Requires: f_mock_chroots_many
+ """
self.b_many_chroots = models.Build(
id=12347,
copr=self.c1, user=self.u1,
diff --git a/frontend/coprs_frontend/tests/test_api/test_build_r.py
b/frontend/coprs_frontend/tests/test_api/test_build_r.py
index bcc5cf7..ae5bee3 100644
--- a/frontend/coprs_frontend/tests/test_api/test_build_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_build_r.py
@@ -20,7 +20,7 @@ class TestBuildResource(CoprsTestCase):
for b_dict in response_object["builds"]
])
- def test_collection_ok(self, f_users, f_coprs, f_builds, f_db,
+ def test_build_collection_ok(self, f_users, f_coprs, f_builds, f_db,
f_users_api, f_mock_chroots):
href = "/api_2/builds"
@@ -35,7 +35,30 @@ class TestBuildResource(CoprsTestCase):
assert expected_ids == self.extract_build_ids(obj)
- def test_collection_by_owner(self, f_users, f_coprs, f_builds, f_db,
+ def test_build_collection_ok_finished(
+ self, f_users, f_coprs, f_mock_chroots, f_builds, f_db):
+
+ self.db.session.commit()
+
+ href_a = "/api_2/builds?is_finished=True"
+ href_b = "/api_2/builds?is_finished=False"
+
+ r_a = self.tc.get(href_a)
+ r_b = self.tc.get(href_b)
+
+ assert r_a.status_code == 200
+ assert r_b.status_code == 200
+ obj_a = json.loads(r_a.data)
+ obj_b = json.loads(r_b.data)
+
+ builds = BuildsLogic.get_multiple().all()
+ expected_ids_a = set([b.id for b in builds if b.ended_on is not None])
+ expected_ids_b = set([b.id for b in builds if b.ended_on is None])
+
+ assert expected_ids_a == self.extract_build_ids(obj_a)
+ assert expected_ids_b == self.extract_build_ids(obj_b)
+
+ def test_build_collection_by_owner(self, f_users, f_coprs, f_builds, f_db,
f_users_api, f_mock_chroots):
names_list = [user.username for user in self.basic_user_list]
@@ -54,8 +77,8 @@ class TestBuildResource(CoprsTestCase):
expected_ids = set([b.id for b in builds])
assert expected_ids == self.extract_build_ids(obj)
- def test_collection_by_project_id(self, f_users, f_coprs, f_builds, f_db,
- f_users_api, f_mock_chroots):
+ def test_build_collection_by_project_id(
+ self, f_users, f_mock_chroots, f_coprs, f_builds, f_db):
project_id_list = [copr.id for copr in self.basic_coprs_list]
for id_ in project_id_list:
@@ -73,8 +96,9 @@ class TestBuildResource(CoprsTestCase):
expected_ids = set([b.id for b in builds])
assert expected_ids == self.extract_build_ids(obj)
- def test_collection_limit_offset(self, f_users, f_coprs, f_builds, f_db,
- f_users_api, f_mock_chroots):
+ def test_build_collection_limit_offset(
+ self, f_users, f_mock_chroots, f_coprs, f_builds, f_db):
+
self.db.session.commit()
builds = BuildsLogic.get_multiple().all()
total = len(builds)
@@ -110,7 +134,7 @@ class TestBuildResource(CoprsTestCase):
r = self.tc.get(href)
assert r.status_code == 200
- def test_post_bad_content_type(
+ def test_build_post_bad_content_type(
self, f_users, f_coprs, f_db, f_mock_chroots,
f_mock_chroots_many, f_build_many_chroots,
f_users_api):
@@ -128,7 +152,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r0.status_code == 400
- def test_post_json_bad_url(
+ def test_build_post_json_bad_url(
self, f_users, f_coprs, f_db, f_mock_chroots,
f_mock_chroots_many, f_build_many_chroots,
f_users_api):
@@ -147,7 +171,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r0.status_code == 400
- def test_post_json(
+ def test_build_post_json(
self, f_users, f_coprs, f_db, f_mock_chroots,
f_mock_chroots_many, f_build_many_chroots,
f_users_api):
@@ -173,7 +197,7 @@ class TestBuildResource(CoprsTestCase):
metadata["srpm_url"]
assert build_dict["source_type"] == "srpm_link"
- def test_post_json_on_wrong_user(
+ def test_build_post_json_on_wrong_user(
self, f_users, f_coprs, f_db, f_mock_chroots,
f_mock_chroots_many, f_build_many_chroots,
f_users_api):
@@ -196,7 +220,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r0.status_code == 403
- def test_post_json_on_project_during_action(
+ def test_build_post_json_on_project_during_action(
self, f_users, f_coprs, f_db, f_mock_chroots,
f_mock_chroots_many, f_build_many_chroots,
f_users_api):
@@ -216,7 +240,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r0.status_code == 400
- def test_post_multipart_wrong_user(
+ def test_build_post_multipart_wrong_user(
self, f_users, f_coprs, f_builds, f_db, f_mock_chroots,
f_mock_chroots_many, f_build_many_chroots,
f_users_api):
@@ -242,7 +266,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r0.status_code == 403
- def test_post_multipart_on_project_during_action(
+ def test_build_post_multipart_on_project_during_action(
self, f_users, f_coprs, f_builds, f_db, f_mock_chroots,
f_mock_chroots_many, f_build_many_chroots,
f_users_api):
@@ -267,7 +291,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r0.status_code == 400
- def test_post_multipart(
+ def test_build_post_multipart(
self, f_users, f_coprs, f_builds, f_db, f_mock_chroots,
f_mock_chroots_many, f_build_many_chroots,
f_users_api):
@@ -303,7 +327,7 @@ class TestBuildResource(CoprsTestCase):
assert set(chroot_name_list) == build_chroots_names
assert len(chroot_name_list) == len(build_chroots_obj["build_tasks"])
- def test_post_multipart_missing_file(
+ def test_build_post_multipart_missing_file(
self,f_users, f_coprs, f_builds, f_db,
f_users_api, f_mock_chroots):
@@ -322,7 +346,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r0.status_code == 400
- def test_post_multipart_missing_metadata(
+ def test_build_post_multipart_missing_metadata(
self,f_users, f_coprs, f_builds, f_db,
f_users_api, f_mock_chroots):
data = {
@@ -337,7 +361,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r0.status_code == 400
- def test_get_one_build(self, f_users, f_coprs, f_builds, f_db,
+ def test_build_get_one(self, f_users, f_coprs, f_builds, f_db,
f_users_api, f_mock_chroots):
build_id_list = [b.id for b in self.basic_builds]
@@ -351,7 +375,7 @@ class TestBuildResource(CoprsTestCase):
assert obj["build"]["id"] == b_id
assert obj["_links"]["self"]["href"] == href
- def test_get_one_build_with_tasks(self, f_users, f_coprs, f_builds, f_db,
+ def test_build_get_one_with_tasks(self, f_users, f_coprs, f_builds, f_db,
f_users_api, f_mock_chroots):
build_id_list = [b.id for b in self.basic_builds]
@@ -366,7 +390,7 @@ class TestBuildResource(CoprsTestCase):
assert obj["_links"]["self"]["href"] == href
assert "build_tasks" in obj
- def test_get_one_build_not_found(self, f_users, f_coprs, f_builds, f_db,
+ def test_build_get_one_not_found(self, f_users, f_coprs, f_builds, f_db,
f_users_api, f_mock_chroots):
build_id_list = [b.id for b in self.basic_builds]
max_id = max(build_id_list) + 1
@@ -379,7 +403,7 @@ class TestBuildResource(CoprsTestCase):
r = self.tc.get(href)
assert r.status_code == 404
- def test_delete_build_ok(self, f_users, f_coprs,
+ def test_build_delete_ok(self, f_users, f_coprs,
f_mock_chroots, f_builds,f_users_api, ):
self.db.session.commit()
@@ -394,7 +418,7 @@ class TestBuildResource(CoprsTestCase):
r2 = self.tc.get(href)
assert r2.status_code == 404
- def test_delete_build_wrong_user(self, f_users, f_coprs,
+ def test_build_delete_wrong_user(self, f_users, f_coprs,
f_mock_chroots, f_builds,f_users_api, ):
login = self.u2.api_login
@@ -409,7 +433,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r.status_code == 403
- def test_delete_build_in_progress(self, f_users, f_coprs,
+ def test_build_delete_in_progress(self, f_users, f_coprs,
f_mock_chroots, f_builds,f_users_api, ):
login = self.u2.api_login
@@ -424,7 +448,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r.status_code == 400
- def test_put_build_wrong_user(
+ def test_build_put_wrong_user(
self, f_users, f_coprs,
f_mock_chroots, f_builds,f_users_api, ):
@@ -453,7 +477,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r.status_code == 403
- def test_put_build_not_found(
+ def test_build_put_not_found(
self, f_users, f_coprs,
f_mock_chroots, f_builds,f_users_api, ):
@@ -469,7 +493,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r.status_code == 404
- def test_put_cancel_build(
+ def test_build_put_cancel(
self, f_users, f_coprs,
f_mock_chroots, f_builds,f_users_api, ):
@@ -499,7 +523,7 @@ class TestBuildResource(CoprsTestCase):
obj = json.loads(r2.data)
assert obj["build"]["state"] == "canceled"
- def test_put_cancel_build_wrong_state(
+ def test_build_put_cancel_wrong_state(
self, f_users, f_coprs,
f_mock_chroots, f_builds,f_users_api, ):
diff --git a/frontend/coprs_frontend/tests/test_api/test_build_task_r.py
b/frontend/coprs_frontend/tests/test_api/test_build_task_r.py
index 253ed95..1ffc37e 100644
--- a/frontend/coprs_frontend/tests/test_api/test_build_task_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_build_task_r.py
@@ -6,6 +6,7 @@ from marshmallow import pprint
import pytest
import sqlalchemy
+from coprs.helpers import StatusEnum
from coprs.logic.users_logic import UsersLogic
from coprs.logic.coprs_logic import CoprsLogic
@@ -18,7 +19,7 @@ class TestBuildTaskResource(CoprsTestCase):
def test_collection_ok(self, f_users, f_coprs, f_mock_chroots, f_builds, f_db,
f_users_api):
- href = "/api_2/build_tasks?build_id=1&limit=5"
+ href = "/api_2/build_tasks?build_id=1"
bc_list = copy.deepcopy(self.b1_bc)
self.db.session.commit()
@@ -27,6 +28,81 @@ class TestBuildTaskResource(CoprsTestCase):
assert r0.status_code == 200
obj = json.loads(r0.data)
assert len(obj["build_tasks"]) == len(bc_list)
+
+ def test_collection_ok_default_limit(self, f_users, f_coprs, f_mock_chroots,
f_builds, f_db,
+ f_users_api):
+
+ self.db.session.commit()
+ href_tpl = "/api_2/build_tasks?limit={}"
+ expected = href_tpl.format(100)
+
+ for val in [-1, 0, 100, 105, 1000]:
+ href = href_tpl.format(val)
+
+ r0 = self.tc.get(href)
+ assert r0.status_code == 200
+ obj = json.loads(r0.data)
+ assert obj["_links"]["self"]["href"] ==
expected
+
+ def test_collection_ok_by_state(
+ self, f_users, f_coprs,
+ f_mock_chroots_many,
+ f_build_many_chroots,
+ f_db,
+ f_users_api):
+
+ self.db.session.commit()
+ for status in StatusEnum.vals.values():
+ expected_chroots = set([
+ name
+ for name, chroot_status in
+ self.status_by_chroot.items()
+ if chroot_status == status
+ ])
+
+ href =
"/api_2/build_tasks?state={}&limit=50".format(StatusEnum(status))
+
+ r0 = self.tc.get(href)
+ assert r0.status_code == 200
+ obj = json.loads(r0.data)
+ assert len(obj["build_tasks"]) == len(expected_chroots)
+ assert set(bt["build_task"]["chroot_name"]
+ for bt in obj["build_tasks"]) == expected_chroots
+ assert obj["_links"]["self"]["href"] == href
+
+ def test_collection_ok_by_project(
+ self, f_users, f_coprs, f_mock_chroots, f_builds,
+ f_users_api, f_db):
+
+ href = "/api_2/build_tasks?project_id=1&limit=50"
+ bc_list = copy.deepcopy(self.b1_bc)
+ bc_list.extend(copy.deepcopy(self.b2_bc))
+
+ self.db.session.commit()
+
+ r0 = self.tc.get(href)
+ assert r0.status_code == 200
+ obj = json.loads(r0.data)
+ assert len(obj["build_tasks"]) == len(bc_list)
+ assert obj["_links"]["self"]["href"] == href
+
+ def test_collection_ok_by_owner(
+ self, f_users, f_coprs, f_mock_chroots, f_builds,
+ f_users_api, f_db):
+
+ href =
"/api_2/build_tasks?owner={}&limit=50".format(self.u2.username)
+ bc_list_len = sum(
+ len(b.build_chroots)
+ for b in self.basic_builds
+ if b.copr.owner == self.u2
+ )
+
+ self.db.session.commit()
+
+ r0 = self.tc.get(href)
+ assert r0.status_code == 200
+ obj = json.loads(r0.data)
+ assert len(obj["build_tasks"]) == bc_list_len
assert obj["_links"]["self"]["href"] == href
def test_post_not_allowed(self, f_users, f_coprs, f_mock_chroots, f_builds, f_db,