[copr] master: [frontend][api] Added PUT method to /builds/<id> resource (5ae4b8e)
by vgologuz@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit 5ae4b8e4fd7b70de86563d3105432763d4b76dc1
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Mon Aug 31 16:25:32 2015 +0200
[frontend][api] Added PUT method to /builds/<id> resource
>---------------------------------------------------------------
frontend/coprs_frontend/coprs/exceptions.py | 4 +
frontend/coprs_frontend/coprs/helpers.py | 1 +
.../coprs_frontend/coprs/logic/builds_logic.py | 3 +
.../coprs/rest_api/resources/build.py | 22 ++++-
.../coprs/rest_api/resources/project.py | 2 -
.../coprs_frontend/tests/test_api/test_build_r.py | 110 ++++++++++++++++++--
.../test_views/test_coprs_ns/test_coprs_builds.py | 10 ++-
7 files changed, 140 insertions(+), 12 deletions(-)
diff --git a/frontend/coprs_frontend/coprs/exceptions.py b/frontend/coprs_frontend/coprs/exceptions.py
index 8806c1c..8216e3a 100644
--- a/frontend/coprs_frontend/coprs/exceptions.py
+++ b/frontend/coprs_frontend/coprs/exceptions.py
@@ -18,6 +18,10 @@ class InsufficientRightsException(BaseException):
pass
+class RequestCannotBeExecuted(Exception):
+ pass
+
+
class ActionInProgressException(BaseException):
def __init__(self, msg, action):
diff --git a/frontend/coprs_frontend/coprs/helpers.py b/frontend/coprs_frontend/coprs/helpers.py
index c5d614f..7d253af 100644
--- a/frontend/coprs_frontend/coprs/helpers.py
+++ b/frontend/coprs_frontend/coprs/helpers.py
@@ -161,6 +161,7 @@ def chroot_to_branch(chroot):
os = "el"
return "{}{}".format(os, version)
+
def branch_to_os_version(branch):
os = None
version = None
diff --git a/frontend/coprs_frontend/coprs/logic/builds_logic.py b/frontend/coprs_frontend/coprs/logic/builds_logic.py
index 250f82e..48a11da 100644
--- a/frontend/coprs_frontend/coprs/logic/builds_logic.py
+++ b/frontend/coprs_frontend/coprs/logic/builds_logic.py
@@ -408,6 +408,9 @@ class BuildsLogic(object):
if not user.can_build_in(build.copr):
raise exceptions.InsufficientRightsException(
"You are not allowed to cancel this build.")
+ if not build.cancelable:
+ raise exceptions.RequestCannotBeExecuted(
+ "Cannot cancel build {}".format(build.id))
build.canceled = True
for chroot in build.build_chroots:
chroot.status = 2 # canceled
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/build.py b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
index 80e5b17..a12a96e 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/build.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
@@ -6,7 +6,7 @@ from flask import url_for, make_response
# from flask_restful_swagger import swagger
from coprs import db, models
-from coprs.exceptions import ActionInProgressException, InsufficientRightsException
+from coprs.exceptions import ActionInProgressException, InsufficientRightsException, RequestCannotBeExecuted
from coprs.logic.coprs_logic import CoprsLogic
from coprs.logic.builds_logic import BuildsLogic
from coprs.logic.users_logic import UsersLogic
@@ -193,6 +193,24 @@ class BuildR(Resource):
return "", 204
+ @rest_api_auth_required
+ def put(self, build_id):
+ build = get_one_safe(BuildsLogic.get(build_id),
+ "Not found build with id: {}".format(build_id))
+ """:type : models.Build """
+ build_dict = mm_deserialize(BuildSchema(), flask.request.data).data
+ try:
+ if not build.canceled and build_dict["state"] == "canceled":
+ BuildsLogic.cancel_build(flask.g.user, build)
+ db.session.commit()
+ except (RequestCannotBeExecuted, ActionInProgressException) as err:
+ db.session.rollback()
+ raise CannotProcessRequest("Cannot update build due to: {}"
+ .format(err))
+ except InsufficientRightsException as err:
+ raise AccessForbidden("Failed to update build: {}".format(err))
-
+ resp = make_response("", 201)
+ resp.headers["Location"] = url_for(".buildr", build_id=build_id)
+ return resp
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/project.py b/frontend/coprs_frontend/coprs/rest_api/resources/project.py
index 7a3f293..92a2d3c 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/project.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/project.py
@@ -80,8 +80,6 @@ class ProjectListR(Resource):
owner = flask.g.user
result = mm_deserialize(ProjectSchema(), flask.request.data)
- if result.errors:
- return "Failed to parse request", 400
# todo check that chroots are available
req = result.data
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 406b7a0..a2067eb 100644
--- a/frontend/coprs_frontend/tests/test_api/test_build_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_build_r.py
@@ -3,8 +3,9 @@ from cStringIO import StringIO
import json
import math
import random
+from marshmallow import pprint
-from coprs.helpers import BuildSourceEnum
+from coprs.helpers import BuildSourceEnum, StatusEnum
from coprs.logic.coprs_logic import CoprsLogic
from coprs.logic.builds_logic import BuildsLogic
from tests.coprs_test_case import CoprsTestCase
@@ -366,7 +367,6 @@ class TestBuildResource(CoprsTestCase):
def test_delete_build_ok(self, f_users, f_coprs,
f_mock_chroots, f_builds,f_users_api, ):
-
self.db.session.commit()
b_id = self.b1.id
href = "/api_2/builds/{}".format(b_id)
@@ -408,10 +408,106 @@ class TestBuildResource(CoprsTestCase):
login=login, token=token,
)
assert r.status_code == 400
- print(r.data)
- # test_put_build_wrong_user
- # test_put_build_not_found
- # test_put_cancel_build
- # test_put_cancel_build_wrong_state
+ def test_put_build_wrong_user(
+ self, f_users, f_coprs,
+ f_mock_chroots, f_builds,f_users_api, ):
+
+ login = self.u2.api_login
+ token = self.u2.api_token
+
+ for bc in self.b1_bc:
+ bc.status = StatusEnum("pending")
+ bc.ended_on = None
+
+ self.b1.ended_on = None
+ self.db.session.add_all(self.b1_bc)
+ self.db.session.add(self.b1)
+
+ self.db.session.commit()
+
+ href = "/api_2/builds/{}".format(self.b1.id)
+ build_dict = {
+ "state": "canceled"
+ }
+ r = self.request_rest_api_with_auth(
+ href,
+ method="put",
+ login=login, token=token,
+ content=build_dict
+ )
+ assert r.status_code == 403
+
+ def test_put_build_not_found(
+ self, f_users, f_coprs,
+ f_mock_chroots, f_builds,f_users_api, ):
+
+ self.db.session.commit()
+ href = "/api_2/builds/{}".format(10005000)
+ build_dict = {
+ "state": "canceled"
+ }
+ r = self.request_rest_api_with_auth(
+ href,
+ method="put",
+ content=build_dict
+ )
+ assert r.status_code == 404
+
+ def test_put_cancel_build(
+ self, f_users, f_coprs,
+ f_mock_chroots, f_builds,f_users_api, ):
+
+ for bc in self.b1_bc:
+ bc.status = StatusEnum("pending")
+ bc.ended_on = None
+
+ self.b1.ended_on = None
+ self.db.session.add_all(self.b1_bc)
+ self.db.session.add(self.b1)
+
+ self.db.session.commit()
+
+ href = "/api_2/builds/{}".format(self.b1.id)
+ build_dict = {
+ "state": "canceled"
+ }
+ r = self.request_rest_api_with_auth(
+ href,
+ method="put",
+ content=build_dict
+ )
+ assert r.status_code == 201
+
+ r2 = self.tc.get(r.headers["Location"])
+ assert r2.status_code == 200
+ obj = json.loads(r2.data)
+ assert obj["build"]["state"] == "canceled"
+
+ def test_put_cancel_build_wrong_state(
+ self, f_users, f_coprs,
+ f_mock_chroots, f_builds,f_users_api, ):
+
+ self.b1.ended_on = None
+ old_state = self.b1.state
+ self.db.session.add_all(self.b1_bc)
+ self.db.session.add(self.b1)
+
+ self.db.session.commit()
+
+ href = "/api_2/builds/{}".format(self.b1.id)
+ build_dict = {
+ "state": "canceled"
+ }
+ r = self.request_rest_api_with_auth(
+ href,
+ method="put",
+ content=build_dict
+ )
+ assert r.status_code == 400
+
+ r2 = self.tc.get(href)
+ assert r2.status_code == 200
+ obj = json.loads(r2.data)
+ assert obj["build"]["state"] == old_state
diff --git a/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py b/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
index aafc17c..7d0e1be 100644
--- a/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
+++ b/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
@@ -1,5 +1,6 @@
import json
from coprs import models
+from coprs.helpers import StatusEnum
from tests.coprs_test_case import CoprsTestCase, TransactionDecorator
@@ -89,6 +90,10 @@ class TestCoprCancelBuild(CoprsTestCase):
f_mock_chroots,
f_builds, f_db):
+ for bc in self.b1_bc:
+ bc.status = StatusEnum("pending")
+ bc.ended_on = None
+ self.db.session.add_all(self.b1_bc)
self.db.session.add_all([self.u1, self.c1, self.b1])
self.test_client.post("/coprs/{0}/{1}/cancel_build/{2}/"
.format(self.u1.name, self.c1.name, self.b1.id),
@@ -102,7 +107,10 @@ class TestCoprCancelBuild(CoprsTestCase):
f_coprs,
f_mock_chroots,
f_builds, f_db):
-
+ for bc in self.b1_bc:
+ bc.status = StatusEnum("pending")
+ bc.ended_on = None
+ self.db.session.add_all(self.b1_bc)
self.db.session.add_all([self.u1, self.c1, self.b1])
self.test_client.post("/coprs/{0}/{1}/cancel_build/{2}/"
.format(self.u1.name, self.c1.name, self.b1.id),
8 years, 7 months
[copr] master: [frontend][api] Added DELETE method to /builds/<id> resource (c8a01c8)
by vgologuz@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit c8a01c8354fdfc991b09f96d33f9489147385ae2
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Mon Aug 31 14:42:51 2015 +0200
[frontend][api] Added DELETE method to /builds/<id> resource
>---------------------------------------------------------------
.../coprs/rest_api/resources/build.py | 31 ++++----
.../coprs_frontend/tests/test_api/test_build_r.py | 79 +++++++++++++++++---
2 files changed, 86 insertions(+), 24 deletions(-)
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/build.py b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
index 5c2a2b5..80e5b17 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/build.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
@@ -172,24 +172,27 @@ class BuildListR(Resource):
class BuildR(Resource):
def get(self, build_id):
-
build = get_one_safe(BuildsLogic.get(build_id),
"Not found build with id: {}".format(build_id))
return render_build(build)
+ @rest_api_auth_required
+ def delete(self, build_id):
+ build = get_one_safe(BuildsLogic.get(build_id),
+ "Not found build with id: {}".format(build_id))
+ try:
+ BuildsLogic.delete_build(flask.g.user, build)
+ db.session.commit()
+ except ActionInProgressException as err:
+ db.session.rollback()
+ raise CannotProcessRequest("Cannot delete build due to: {}"
+ .format(err))
+ except InsufficientRightsException as err:
+ raise AccessForbidden("Failed to delete build: {}".format(err))
+
+ return "", 204
+
+
-# to get build details and cancel individual build chroots
-# class BuildChrootR(Resource):
-# def get(self, owner, project, name):
-# copr = get_one_safe(CoprsLogic.get(flask.g.user, owner, project),
-# "Copr {}/{} not found".format(owner, project))
-# chroot = get_one_safe(CoprChrootsLogic.get(copr, name))
-#
-# return {
-# "chroot": chroot.to_dict(),
-# "links": {
-# "self": bp_url_for(BuildChrootR.endpoint, owner=owner, project=project, name=name)
-# }
-# }
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 0d9c9b9..406b7a0 100644
--- a/frontend/coprs_frontend/tests/test_api/test_build_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_build_r.py
@@ -1,20 +1,13 @@
# coding: utf-8
from cStringIO import StringIO
-
import json
-from marshmallow import pprint
import math
+import random
-import pytest
-import sqlalchemy
-from coprs import models
from coprs.helpers import BuildSourceEnum
-
-from coprs.logic.users_logic import UsersLogic
from coprs.logic.coprs_logic import CoprsLogic
from coprs.logic.builds_logic import BuildsLogic
-
-from tests.coprs_test_case import CoprsTestCase, TransactionDecorator
+from tests.coprs_test_case import CoprsTestCase
class TestBuildResource(CoprsTestCase):
@@ -343,7 +336,7 @@ class TestBuildResource(CoprsTestCase):
)
assert r0.status_code == 400
- def test_get_one(self, f_users, f_coprs, f_builds, f_db,
+ def test_get_one_build(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]
@@ -356,3 +349,69 @@ class TestBuildResource(CoprsTestCase):
obj = json.loads(r.data)
assert obj["build"]["id"] == b_id
assert obj["_links"]["self"]["href"] == href
+
+ def test_get_one_build_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
+ self.db.session.commit()
+
+ for _ in range(10):
+ fake_id = random.randint(max_id, max_id * 10)
+ href = "/api_2/builds/{}".format(fake_id)
+
+ r = self.tc.get(href)
+ assert r.status_code == 404
+
+ def test_delete_build_ok(self, f_users, f_coprs,
+ f_mock_chroots, f_builds,f_users_api, ):
+
+
+ self.db.session.commit()
+ b_id = self.b1.id
+ href = "/api_2/builds/{}".format(b_id)
+ r = self.request_rest_api_with_auth(
+ href,
+ method="delete",
+ )
+ assert r.status_code == 204
+
+ r2 = self.tc.get(href)
+ assert r2.status_code == 404
+
+ def test_delete_build_wrong_user(self, f_users, f_coprs,
+ f_mock_chroots, f_builds,f_users_api, ):
+
+ login = self.u2.api_login
+ token = self.u2.api_token
+ self.db.session.commit()
+ b_id = self.b1.id
+ href = "/api_2/builds/{}".format(b_id)
+ r = self.request_rest_api_with_auth(
+ href,
+ method="delete",
+ login=login, token=token,
+ )
+ assert r.status_code == 403
+
+ def test_delete_build_in_progress(self, f_users, f_coprs,
+ f_mock_chroots, f_builds,f_users_api, ):
+
+ login = self.u2.api_login
+ token = self.u2.api_token
+ self.db.session.commit()
+ b_id = self.b3.id
+ href = "/api_2/builds/{}".format(b_id)
+ r = self.request_rest_api_with_auth(
+ href,
+ method="delete",
+ login=login, token=token,
+ )
+ assert r.status_code == 400
+ print(r.data)
+
+ # test_put_build_wrong_user
+ # test_put_build_not_found
+ # test_put_cancel_build
+ # test_put_cancel_build_wrong_state
+
8 years, 7 months
[copr] master: [frontend][api] Update tests relatedto BuildsLogic (cd3f8bb)
by vgologuz@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit cd3f8bb070a91077418c03fd4c14687555a9b3b7
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Mon Aug 31 13:43:28 2015 +0200
[frontend][api] Update tests relatedto BuildsLogic
>---------------------------------------------------------------
frontend/coprs_frontend/tests/coprs_test_case.py | 17 +++++++----
.../tests/test_logic/test_builds_logic.py | 6 ++-
.../test_backend_ns/test_backend_general.py | 25 ++++------------
.../test_views/test_coprs_ns/test_coprs_builds.py | 32 ++++++++++++++++++-
4 files changed, 51 insertions(+), 29 deletions(-)
diff --git a/frontend/coprs_frontend/tests/coprs_test_case.py b/frontend/coprs_frontend/tests/coprs_test_case.py
index dedc68b..a6dff96 100644
--- a/frontend/coprs_frontend/tests/coprs_test_case.py
+++ b/frontend/coprs_frontend/tests/coprs_test_case.py
@@ -225,13 +225,14 @@ class CoprsTestCase(object):
buildchroot = models.BuildChroot(
build=build,
mock_chroot=chroot,
- status=status)
+ status=status,
+ git_hash="12345",
+ )
- if build is self.b1:
- buildchroot.started_on = 139086644000
- if build is self.b2:
+ if build is [self.b1, self.b2]:
buildchroot.started_on = 139086644000
buildchroot.ended_on = 149086644000
+ build.ended_on = 149086644000
build_chroots.append(buildchroot)
self.db.session.add(buildchroot)
@@ -265,7 +266,9 @@ class CoprsTestCase(object):
buildchroot = models.BuildChroot(
build=self.b_few_chroots,
mock_chroot=chroot,
- status=self.status_by_chroot[chroot.name])
+ status=self.status_by_chroot[chroot.name],
+ git_hash="12345",
+ )
self.db.session.add(buildchroot)
self.db.session.add(self.b_few_chroots)
@@ -303,7 +306,9 @@ class CoprsTestCase(object):
buildchroot = models.BuildChroot(
build=self.b_many_chroots,
mock_chroot=chroot,
- status=self.status_by_chroot[chroot.name])
+ status=self.status_by_chroot[chroot.name],
+ git_hash="12345",
+ )
self.db.session.add(buildchroot)
self.db.session.add(self.b_many_chroots)
diff --git a/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py b/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
index b99955d..97d3ab2 100644
--- a/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
+++ b/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
@@ -143,6 +143,7 @@ class TestBuildsLogic(CoprsTestCase):
self.b4.pkgs = "http://example.com/copr-keygen-1.58-1.fc20.src.rpm"
self.b4.ended_on = time.time()
+ expected_dir = self.b4.result_dir_name
for bc in self.b4_bc:
bc.status = StatusEnum("succeeded")
bc.ended_on = time.time()
@@ -166,7 +167,7 @@ class TestBuildsLogic(CoprsTestCase):
action = ActionsLogic.get_many().one()
delete_data = json.loads(action.data)
assert "chroots" in delete_data
- assert "copr-keygen-1.58-1.fc20" == delete_data["src_pkg_name"]
+ assert delete_data["result_dir_name"] == expected_dir
assert expected_chroots_to_delete == set(delete_data["chroots"])
with pytest.raises(NoResultFound):
@@ -176,6 +177,7 @@ class TestBuildsLogic(CoprsTestCase):
self, f_users, f_coprs, f_mock_chroots, f_builds, f_db):
self.b1.pkgs = "http://example.com/copr-keygen-1.58-1.fc20.src.rpm"
+ expected_dir = self.b1.result_dir_name
self.db.session.add(self.b1)
self.db.session.commit()
@@ -191,7 +193,7 @@ class TestBuildsLogic(CoprsTestCase):
action = ActionsLogic.get_many().one()
delete_data = json.loads(action.data)
assert "chroots" in delete_data
- assert "copr-keygen-1.58-1.fc20" == delete_data["src_pkg_name"]
+ assert delete_data["result_dir_name"] == expected_dir
assert expected_chroots_to_delete == set(delete_data["chroots"])
with pytest.raises(NoResultFound):
diff --git a/frontend/coprs_frontend/tests/test_views/test_backend_ns/test_backend_general.py b/frontend/coprs_frontend/tests/test_views/test_backend_ns/test_backend_general.py
index ca4ce18..3b8a748 100644
--- a/frontend/coprs_frontend/tests/test_views/test_backend_ns/test_backend_general.py
+++ b/frontend/coprs_frontend/tests/test_views/test_backend_ns/test_backend_general.py
@@ -55,6 +55,8 @@ class TestUpdateBuilds(CoprsTestCase):
{
"id": 1,
"copr_id": 2,
+ "chroot": "fedora-18-x86_64",
+ "status": 6,
"started_on": 139086644000
},
{
@@ -69,11 +71,13 @@ class TestUpdateBuilds(CoprsTestCase):
"id": 123321,
"copr_id": 1,
"status": 0,
+ "chroot": "fedora-18-x86_64",
"ended_on": 139086644000
},
{
"id": 1234321,
"copr_id": 2,
+ "chroot": "fedora-18-x86_64",
"results": "http://server/results/foo/bar/",
"started_on": 139086644000
}
@@ -86,23 +90,7 @@ class TestUpdateBuilds(CoprsTestCase):
data="")
assert "You have to provide the correct password" in r.data
- def test_update_build_started(self, f_users, f_coprs, f_mock_chroots, f_builds, f_db):
- self.b1.started_on = None
- self.db.session.add(self.b1)
- self.db.session.commit()
-
- r = self.tc.post("/backend/update/",
- content_type="application/json",
- headers=self.auth_header,
- data=self.data1)
- assert json.loads(r.data)["updated_builds_ids"] == [1]
- assert json.loads(r.data)["non_existing_builds_ids"] == []
-
- updated = self.models.Build.query.filter(
- self.models.Build.id == 1).one()
-
- assert updated.results == "http://server/results/foo/bar/"
- assert updated.chroots_started_on == {'fedora-18-x86_64': 139086644000}
+ # todo: add test for `backend/starting_build/`
def test_update_build_ended(self, f_users, f_coprs, f_mock_chroots,
f_builds, f_db):
@@ -114,10 +102,9 @@ class TestUpdateBuilds(CoprsTestCase):
assert json.loads(r.data)["updated_builds_ids"] == [1]
assert json.loads(r.data)["non_existing_builds_ids"] == []
- # import ipdb; ipdb.set_trace()
updated = self.models.Build.query.filter(
self.models.Build.id == 1).one()
- # import ipdb; ipdb.set_trace()
+
assert updated.status == 1
assert updated.chroots_ended_on == {'fedora-18-x86_64': 149086644000}
diff --git a/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py b/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
index 7bb818f..aafc17c 100644
--- a/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
+++ b/frontend/coprs_frontend/tests/test_views/test_coprs_ns/test_coprs_builds.py
@@ -115,12 +115,15 @@ class TestCoprCancelBuild(CoprsTestCase):
class TestCoprDeleteBuild(CoprsTestCase):
@TransactionDecorator("u1")
- def test_copr_build_submitter_can_delete_build(self, f_users,
+ def test_copr_build_submitter_can_delete_build_old(self, f_users,
f_coprs, f_mock_chroots,
- f_builds, f_db):
+ f_builds):
pkgs = "http://example.com/one.src.rpm"
self.b1.pkgs = pkgs
+ for bc in self.b1_bc:
+ bc.git_hash = None
+ self.db.session.add_all(self.b1_bc)
self.db.session.add_all([self.u1, self.c1, self.b1])
self.db.session.commit()
@@ -139,6 +142,31 @@ class TestCoprDeleteBuild(CoprsTestCase):
assert act.old_value == "user1/foocopr"
assert json.loads(act.data)["src_pkg_name"] == self.b1.src_pkg_name
+ @TransactionDecorator("u1")
+ def test_copr_build_submitter_can_delete_build(self, f_users,
+ f_coprs, f_mock_chroots,
+ f_builds):
+ self.db.session.add_all([self.u1, self.c1, self.b1])
+ self.db.session.commit()
+ expected_dir = self.b1.result_dir_name
+ b_id = self.b1.id
+ url = "/coprs/{0}/{1}/delete_build/{2}/".format(self.u1.name, self.c1.name, b_id)
+
+ r = self.test_client.post(
+ url, data={}, follow_redirects=True)
+ assert r.status_code == 200
+
+ b = (
+ self.models.Build.query
+ .filter(self.models.Build.id == b_id)
+ .first()
+ )
+ assert b is None
+ act = self.models.Action.query.first()
+ assert act.object_type == "build"
+ assert act.old_value == "user1/foocopr"
+ assert json.loads(act.data)["result_dir_name"] == expected_dir
+
@TransactionDecorator("u2")
def test_copr_build_non_submitter_cannot_delete_build(self, f_users,
f_coprs,
8 years, 7 months
[copr] master: [frontend][api] Implemented and tested build creation. (POST to /builds) (6548b5c)
by vgologuz@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit 6548b5cdf68a15f7e50b907ef708de792c8aed47
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Fri Aug 28 12:12:21 2015 +0200
[frontend][api] Implemented and tested build creation. (POST to /builds)
>---------------------------------------------------------------
.../coprs_frontend/coprs/logic/builds_logic.py | 49 +++++--
frontend/coprs_frontend/coprs/logic/coprs_logic.py | 12 +-
.../coprs/rest_api/resources/build.py | 39 ++++-
frontend/coprs_frontend/coprs/rest_api/schemas.py | 2 +-
.../coprs/views/coprs_ns/coprs_builds.py | 57 +++++---
.../coprs_frontend/tests/test_api/test_build_r.py | 152 +++++++++++++++++++-
6 files changed, 264 insertions(+), 47 deletions(-)
diff --git a/frontend/coprs_frontend/coprs/logic/builds_logic.py b/frontend/coprs_frontend/coprs/logic/builds_logic.py
index cd21a6d..250f82e 100644
--- a/frontend/coprs_frontend/coprs/logic/builds_logic.py
+++ b/frontend/coprs_frontend/coprs/logic/builds_logic.py
@@ -174,10 +174,45 @@ class BuildsLogic(object):
return models.Build.query.get(build_id)
@classmethod
+ def create_new_from_url(cls, user, copr, srpm_url,
+ chroot_names=None, **build_options):
+ """
+ :type user: models.User
+ :type copr: models.Copr
+
+ :type chroot_names: List[str]
+
+ :rtype: models.Build
+ """
+ # check which chroots we need
+ chroots = []
+ for chroot in copr.active_chroots:
+ if chroot.name in chroot_names:
+ chroots.append(chroot)
+
+ source_type = helpers.BuildSourceEnum("srpm_link")
+ source_json = json.dumps({"url": srpm_url})
+
+ # try:
+ build = cls.add(
+ user=user,
+ pkgs=srpm_url,
+ copr=copr,
+ chroots=chroots,
+ source_type=source_type,
+ source_json=source_json,
+ enable_net=build_options.get("enabled_net", True))
+
+ if user.proven:
+ if "timeout" in build_options:
+ build.timeout = build_options["timeout"]
+
+ return build
+
+ @classmethod
def create_new_from_upload(cls, user, copr, f_uploader, orig_filename,
chroot_names=None, **build_options):
"""
-
:type user: models.User
:type copr: models.Copr
:param f_uploader(file_path): function which stores data at the given `file_path`
@@ -195,7 +230,6 @@ class BuildsLogic(object):
tmp_dir=tmp_name,
srpm=filename)
- # import ipdb; ipdb.set_trace()
# check which chroots we need
chroots = []
for chroot in copr.active_chroots:
@@ -218,19 +252,16 @@ class BuildsLogic(object):
if user.proven:
if "timeout" in build_options:
build.timeout = build_options["timeout"]
- except (ActionInProgressException, InsufficientRightsException) as e:
- db.session.rollback()
- shutil.rmtree(tmp)
+
+ except Exception:
+ shutil.rmtree(tmp) # todo: maybe we should delete in some cleanup procedure?
raise
- else:
- flask.flash("New build has been created.")
return build
@classmethod
def add(cls, user, pkgs, copr, source_type=None, source_json=None,
- repos=None, chroots=None,
- memory_reqs=None, timeout=None, enable_net=True,
+ repos=None, chroots=None, timeout=None, enable_net=True,
git_hashes=None):
if chroots is None:
chroots = []
diff --git a/frontend/coprs_frontend/coprs/logic/coprs_logic.py b/frontend/coprs_frontend/coprs/logic/coprs_logic.py
index 35e9b96..0957462 100644
--- a/frontend/coprs_frontend/coprs/logic/coprs_logic.py
+++ b/frontend/coprs_frontend/coprs/logic/coprs_logic.py
@@ -209,6 +209,13 @@ class CoprsLogic(object):
copr, "Can't delete this project,"
" another operation is in progress: {action}")
+ cls.create_delete_action(copr)
+ copr.deleted = True
+
+ return copr
+
+ @classmethod
+ def create_delete_action(cls, copr):
action = models.Action(action_type=helpers.ActionTypeEnum("delete"),
object_type="copr",
object_id=copr.id,
@@ -216,11 +223,8 @@ class CoprsLogic(object):
copr.name),
new_value="",
created_on=int(time.time()))
- copr.deleted = True
-
db.session.add(action)
-
- return copr
+ return action
@classmethod
def exists_for_user(cls, user, coprname, incl_deleted=False):
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/build.py b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
index c5eab02..5c2a2b5 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/build.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
@@ -54,7 +54,7 @@ class BuildListR(Resource):
else:
query = BuildsLogic.get_multiple()
- if "limit" in req_args:
+ if req_args["limit"] is not None:
limit = req_args["limit"]
if limit <= 0 or limit > 100:
limit = 100
@@ -63,7 +63,7 @@ class BuildListR(Resource):
query = query.limit(limit)
- if "offset" in req_args:
+ if req_args["offset"] is not None:
query = query.offset(req_args["offset"])
builds = query.all()
@@ -84,11 +84,34 @@ class BuildListR(Resource):
"""
:return: if of the created build or raise Exception
"""
- build_data = mm_deserialize(BuildCreateFromUrlSchema(), req.data)
- raise NotImplementedError()
+ build_params = mm_deserialize(BuildCreateFromUrlSchema(), req.data).data
+ project_id = build_params["project_id"]
+ project = get_one_safe(CoprsLogic.get_by_id(project_id))
+ """:type : models.Copr """
+ chroot_names = build_params.pop("chroots")
+ srpm_url = build_params.pop("srpm_url")
+ try:
+ build = BuildsLogic.create_new_from_url(
+ flask.g.user, project,
+ srpm_url=srpm_url,
+ chroot_names=chroot_names,
+ **build_params
+ )
+ db.session.commit()
+ except ActionInProgressException as err:
+ db.session.rollback()
+ raise CannotProcessRequest("Cannot create new build due to: {}"
+ .format(err))
+ except InsufficientRightsException as err:
+ db.session.rollback()
+ raise AccessForbidden("User {} cannon create build in project {}: {}"
+ .format(flask.g.user.username,
+ project.full_name, err))
+ return build.id
- def handle_post_multipart(self, req):
+ @staticmethod
+ def handle_post_multipart(req):
"""
:return: if of the created build or raise Exception
"""
@@ -118,12 +141,14 @@ class BuildListR(Resource):
)
db.session.commit()
except ActionInProgressException as err:
+ db.session.rollback()
raise CannotProcessRequest("Cannot create new build due to: {}"
.format(err))
except InsufficientRightsException as err:
- raise AccessForbidden("User {} cannon create build in project {}"
+ db.session.rollback()
+ raise AccessForbidden("User {} cannon create build in project {}: {}"
.format(flask.g.user.username,
- project.full_name))
+ project.full_name, err))
return build.id
diff --git a/frontend/coprs_frontend/coprs/rest_api/schemas.py b/frontend/coprs_frontend/coprs/rest_api/schemas.py
index 057660b..26f4452 100644
--- a/frontend/coprs_frontend/coprs/rest_api/schemas.py
+++ b/frontend/coprs_frontend/coprs/rest_api/schemas.py
@@ -105,4 +105,4 @@ class BuildCreateSchema(BuildSchema):
class BuildCreateFromUrlSchema(BuildCreateSchema):
- source_url = fields.Url()
+ srpm_url = fields.Url(required=True, validate=lambda u: u.startswith("http"))
diff --git a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
index 40ef9bb..2dffef3 100644
--- a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
+++ b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
@@ -148,7 +148,10 @@ def copr_new_build_upload(username, coprname):
)
db.session.commit()
except (ActionInProgressException, InsufficientRightsException) as e:
+ db.session.rollback()
flask.flash(str(e), "error")
+ else:
+ flask.flash("New build has been created.")
return flask.redirect(flask.url_for("coprs_ns.copr_builds",
username=username,
@@ -173,31 +176,43 @@ def copr_new_build(username, coprname):
if not pkgs:
flask.flash("No builds submitted")
else:
- # check which chroots we need
- chroots = []
- for chroot in copr.active_chroots:
- if chroot.name in form.selected_chroots:
- chroots.append(chroot)
+ # # check which chroots we need
+ # chroots = []
+ # for chroot in copr.active_chroots:
+ # if chroot.name in form.selected_chroots:
+ # chroots.append(chroot)
# build each package as a separate build
try:
for pkg in pkgs:
- # create json describing the build source
- source_type = helpers.BuildSourceEnum("srpm_link")
- source_json = json.dumps({"url": pkg})
-
- build = BuildsLogic.add(
- user=flask.g.user,
- pkgs=pkg,
- copr=copr,
- chroots=chroots,
- source_type=source_type,
- source_json=source_json,
- enable_net=form.enable_net.data)
-
- if flask.g.user.proven:
- build.memory_reqs = form.memory_reqs.data
- build.timeout = form.timeout.data
+ build_options = {
+ "enable_net": form.enable_net.data,
+ "timeout": form.timeout.data,
+ }
+ BuildsLogic.create_new_from_url(
+ flask.g.user, copr, pkg,
+ chroot_names=form.selected_chroots,
+ **build_options
+ )
+
+ # # create json describing the build source
+ # source_type = helpers.BuildSourceEnum("srpm_link")
+ # source_json = json.dumps({"url": pkg})
+
+
+
+ # build = BuildsLogic.add(
+ # user=flask.g.user,
+ # pkgs=pkg,
+ # copr=copr,
+ # chroots=chroots,
+ # source_type=source_type,
+ # source_json=source_json,
+ # enable_net=form.enable_net.data)
+ #
+ # if flask.g.user.proven:
+ # build.memory_reqs = form.memory_reqs.data
+ # build.timeout = form.timeout.data
except (ActionInProgressException, InsufficientRightsException) as e:
flask.flash(str(e), "error")
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 5aefd36..0d9c9b9 100644
--- a/frontend/coprs_frontend/tests/test_api/test_build_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_build_r.py
@@ -7,6 +7,7 @@ import math
import pytest
import sqlalchemy
+from coprs import models
from coprs.helpers import BuildSourceEnum
from coprs.logic.users_logic import UsersLogic
@@ -110,16 +111,57 @@ class TestBuildResource(CoprsTestCase):
assert builds[:delta] == obj1["builds"]
assert builds[delta:2 * delta] == obj2["builds"]
- # todo: implement
- def _test_post_json(
- self, f_users, f_coprs, f_builds, f_db, f_mock_chroots,
+ # for coverage
+ href = "/api_2/builds?limit={}".format(1000000)
+ r = self.tc.get(href)
+ assert r.status_code == 200
+
+ def test_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):
+ chroot_name_list = [c.name for c in self.c1.active_chroots]
+ self.db.session.commit()
+ metadata = {
+ "project_id": 1,
+ "srpm_url": "http://example.com/mypkg.src.rpm",
+ "chroots": chroot_name_list
+ }
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ content_type="plain/test"
+ )
+ assert r0.status_code == 400
+
+ def test_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):
+ chroot_name_list = [c.name for c in self.c1.active_chroots]
+ for url in [None, "", "dsafasdga", "gopher://mp.src.rpm"]:
+ metadata = {
+ "project_id": 1,
+ "srpm_url": url,
+ "chroots": chroot_name_list
+ }
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ content=metadata
+ )
+ assert r0.status_code == 400
+
+ def test_post_json(
+ self, f_users, f_coprs, f_db, f_mock_chroots,
f_mock_chroots_many, f_build_many_chroots,
f_users_api):
chroot_name_list = [c.name for c in self.c1.active_chroots]
metadata = {
"project_id": 1,
- "url": "http://example.com/mypkg.src.rpm",
+ "srpm_url": "http://example.com/mypkg.src.rpm",
"chroots": chroot_name_list
}
self.db.session.commit()
@@ -128,8 +170,108 @@ class TestBuildResource(CoprsTestCase):
method="post",
content=metadata
)
- print(r0.data)
assert r0.status_code == 201
+ r1 = self.tc.get(r0.headers["Location"])
+ assert r1.status_code == 200
+ build_obj = json.loads(r1.data)
+ build_dict = build_obj["build"]
+ assert json.loads(build_dict["source_json"])["url"] == \
+ metadata["srpm_url"]
+ assert build_dict["source_type"] == BuildSourceEnum("srpm_link")
+
+ def test_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):
+
+ login = self.u2.api_login
+ token = self.u2.api_token
+
+ chroot_name_list = [c.name for c in self.c1.active_chroots]
+ metadata = {
+ "project_id": 1,
+ "srpm_url": "http://example.com/mypkg.src.rpm",
+ "chroots": chroot_name_list
+ }
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ login=login, token=token,
+ content=metadata,
+ )
+ assert r0.status_code == 403
+
+ def test_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):
+
+ CoprsLogic.create_delete_action(self.c1)
+ chroot_name_list = [c.name for c in self.c1.active_chroots]
+ metadata = {
+ "project_id": 1,
+ "srpm_url": "http://example.com/mypkg.src.rpm",
+ "chroots": chroot_name_list
+ }
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ content=metadata,
+ )
+ assert r0.status_code == 400
+
+ def test_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):
+ chroot_name_list = [c.name for c in self.c1.active_chroots]
+ metadata = {
+ "project_id": 1,
+ "enable_net": True,
+ "chroots": chroot_name_list
+ }
+ data = {
+ "metadata": json.dumps(metadata),
+ "srpm": (StringIO(u'my file contents'), 'hello world.src.rpm')
+ }
+ login = self.u2.api_login
+ token = self.u2.api_token
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ login=login, token=token,
+ content_type="multipart/form-data",
+ data=data
+ )
+ assert r0.status_code == 403
+
+ def test_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):
+
+ CoprsLogic.create_delete_action(self.c1)
+ chroot_name_list = [c.name for c in self.c1.active_chroots]
+ metadata = {
+ "project_id": 1,
+ "enable_net": True,
+ "chroots": chroot_name_list
+ }
+ data = {
+ "metadata": json.dumps(metadata),
+ "srpm": (StringIO(u'my file contents'), 'hello world.src.rpm')
+ }
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ content_type="multipart/form-data",
+ data=data
+ )
+ assert r0.status_code == 400
def test_post_multipart(
self, f_users, f_coprs, f_builds, f_db, f_mock_chroots,
8 years, 7 months
[copr] master: [frontend][api] Implemented and tested build creation through file upload (e200db6)
by vgologuz@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit e200db624cc66a4b4a5e1d7d13ee04b38c7ac06a
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Thu Aug 27 17:52:00 2015 +0200
[frontend][api] Implemented and tested build creation through file upload
>---------------------------------------------------------------
.../coprs_frontend/coprs/logic/builds_logic.py | 76 ++++++++++++----
.../coprs_frontend/coprs/rest_api/exceptions.py | 5 +
.../coprs/rest_api/resources/build.py | 73 ++++++++++++++-
.../coprs/rest_api/resources/project.py | 2 -
frontend/coprs_frontend/coprs/rest_api/schemas.py | 34 +++++---
.../coprs/views/coprs_ns/coprs_builds.py | 59 ++++---------
frontend/coprs_frontend/tests/coprs_test_case.py | 32 +++++--
.../tests/test_api/test_build_chroot_r.py | 1 +
.../coprs_frontend/tests/test_api/test_build_r.py | 95 +++++++++++++++++++-
.../tests/test_api/test_project_r.py | 1 +
.../tests/test_logic/test_builds_logic.py | 2 -
11 files changed, 291 insertions(+), 89 deletions(-)
diff --git a/frontend/coprs_frontend/coprs/logic/builds_logic.py b/frontend/coprs_frontend/coprs/logic/builds_logic.py
index 0369205..cd21a6d 100644
--- a/frontend/coprs_frontend/coprs/logic/builds_logic.py
+++ b/frontend/coprs_frontend/coprs/logic/builds_logic.py
@@ -1,14 +1,17 @@
from collections import defaultdict
+import tempfile
import urlparse
import shutil
import json
import os
import pprint
import time
+import flask
from sqlalchemy import or_
from sqlalchemy import and_
from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.sql import false
+from werkzeug.utils import secure_filename
from coprs import app
from coprs import db
@@ -16,7 +19,7 @@ from coprs import exceptions
from coprs import models
from coprs import helpers
from coprs.constants import DEFAULT_BUILD_TIMEOUT, MAX_BUILD_TIMEOUT
-from coprs.exceptions import MalformedArgumentException
+from coprs.exceptions import MalformedArgumentException, ActionInProgressException, InsufficientRightsException
from coprs.helpers import StatusEnum
from coprs.logic import coprs_logic
@@ -171,6 +174,60 @@ class BuildsLogic(object):
return models.Build.query.get(build_id)
@classmethod
+ def create_new_from_upload(cls, user, copr, f_uploader, orig_filename,
+ chroot_names=None, **build_options):
+ """
+
+ :type user: models.User
+ :type copr: models.Copr
+ :param f_uploader(file_path): function which stores data at the given `file_path`
+ :return:
+ """
+ tmp = tempfile.mkdtemp(dir=app.config["SRPM_STORAGE_DIR"])
+ tmp_name = os.path.basename(tmp)
+ filename = secure_filename(orig_filename)
+ file_path = os.path.join(tmp, filename)
+ f_uploader(file_path)
+
+ # make the pkg public
+ pkg_url = "https://{hostname}/tmp/{tmp_dir}/{srpm}".format(
+ hostname=app.config["PUBLIC_COPR_HOSTNAME"],
+ tmp_dir=tmp_name,
+ srpm=filename)
+
+ # import ipdb; ipdb.set_trace()
+ # check which chroots we need
+ chroots = []
+ for chroot in copr.active_chroots:
+ if chroot.name in chroot_names:
+ chroots.append(chroot)
+
+ # create json describing the build source
+ source_type = helpers.BuildSourceEnum("srpm_upload")
+ source_json = json.dumps({"tmp": tmp_name, "pkg": filename})
+ try:
+ build = cls.add(
+ user=user,
+ pkgs=pkg_url,
+ copr=copr,
+ chroots=chroots,
+ source_type=source_type,
+ source_json=source_json,
+ enable_net=build_options.get("enabled_net", True))
+
+ if user.proven:
+ if "timeout" in build_options:
+ build.timeout = build_options["timeout"]
+ except (ActionInProgressException, InsufficientRightsException) as e:
+ db.session.rollback()
+ shutil.rmtree(tmp)
+ raise
+ else:
+ flask.flash("New build has been created.")
+
+ return build
+
+ @classmethod
def add(cls, user, pkgs, copr, source_type=None, source_json=None,
repos=None, chroots=None,
memory_reqs=None, timeout=None, enable_net=True,
@@ -187,6 +244,7 @@ class BuildsLogic(object):
if not repos:
repos = copr.repos
+ # todo: eliminate pkgs and this check
if " " in pkgs or "\n" in pkgs or "\t" in pkgs or pkgs.strip() != pkgs:
raise exceptions.MalformedArgumentException("Trying to create a build using src_pkg "
"with bad characters. Forgot to split?")
@@ -196,18 +254,6 @@ class BuildsLogic(object):
source_type = helpers.BuildSourceEnum("srpm_link")
source_json = json.dumps({"url":pkgs})
- # We no longer guess package name just from the filename
- #package_name = helpers.parse_package_name(os.path.basename(pkgs))
-
- # And we no longer assign a package to the build (we don't know the package name, right...)
- # This is done after package is imported.
- #package = packages_logic.PackagesLogic.get(copr.id, package_name).first()
-
- #if not package:
- # package = packages_logic.PackagesLogic.add(user, copr, package_name)
- # db.session.add(package)
- # db.session.flush()
-
build = models.Build(
user=user,
pkgs=pkgs,
@@ -215,14 +261,10 @@ class BuildsLogic(object):
repos=repos,
source_type=source_type,
source_json=source_json,
- #package_id=package.id,
submitted_on=int(time.time()),
enable_net=bool(enable_net),
)
- if memory_reqs:
- build.memory_reqs = memory_reqs
-
if timeout:
build.timeout = timeout or DEFAULT_BUILD_TIMEOUT
diff --git a/frontend/coprs_frontend/coprs/rest_api/exceptions.py b/frontend/coprs_frontend/coprs/rest_api/exceptions.py
index 6c96cb2..1752101 100644
--- a/frontend/coprs_frontend/coprs/rest_api/exceptions.py
+++ b/frontend/coprs_frontend/coprs/rest_api/exceptions.py
@@ -47,6 +47,11 @@ class MalformedRequest(ApiError):
super(MalformedRequest, self).__init__(400, data, **kwargs)
+class CannotProcessRequest(ApiError):
+ def __init__(self, data=None, **kwargs):
+ super(CannotProcessRequest, self).__init__(400, data, **kwargs)
+
+
class ServerError(ApiError):
def __init__(self, data=None, **kwargs):
super(ServerError, self).__init__(500, data, **kwargs)
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/build.py b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
index 33fba81..c5eab02 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/build.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
@@ -1,17 +1,21 @@
# coding: utf-8
import flask
-from flask import url_for
+from flask import url_for, make_response
# from flask_restful_swagger import swagger
+from coprs import db, models
+from coprs.exceptions import ActionInProgressException, InsufficientRightsException
from coprs.logic.coprs_logic import CoprsLogic
from coprs.logic.builds_logic import BuildsLogic
from coprs.logic.users_logic import UsersLogic
+from coprs.rest_api.exceptions import MalformedRequest, CannotProcessRequest, AccessForbidden
+from coprs.rest_api.resources.project import rest_api_auth_required
-from coprs.rest_api.schemas import BuildSchema
+from coprs.rest_api.schemas import BuildSchema, BuildCreateSchema, BuildCreateFromUrlSchema
-from coprs.rest_api.util import get_one_safe
+from coprs.rest_api.util import get_one_safe, mm_deserialize
from flask_restful import Resource, reqparse
@@ -76,6 +80,69 @@ class BuildListR(Resource):
},
}
+ def handle_post_json(self, req):
+ """
+ :return: if of the created build or raise Exception
+ """
+ build_data = mm_deserialize(BuildCreateFromUrlSchema(), req.data)
+ raise NotImplementedError()
+
+
+ def handle_post_multipart(self, req):
+ """
+ :return: if of the created build or raise Exception
+ """
+ try:
+ metadata = req.form["metadata"]
+ except KeyError:
+ raise MalformedRequest("Missing build metadata in the request")
+
+ if "srpm" not in req.files:
+ raise MalformedRequest("Missing srpm file in the request")
+ srpm_handle = req.files["srpm"]
+
+ build_params = mm_deserialize(BuildCreateSchema(), metadata).data
+ project_id = build_params["project_id"]
+
+ project = get_one_safe(CoprsLogic.get_by_id(project_id))
+ """:type : models.Copr """
+
+ chroot_names = build_params.pop("chroots")
+ try:
+ build = BuildsLogic.create_new_from_upload(
+ flask.g.user, project,
+ f_uploader=lambda path: srpm_handle.save(path),
+ orig_filename=srpm_handle.filename,
+ chroot_names=chroot_names,
+ **build_params
+ )
+ db.session.commit()
+ except ActionInProgressException as err:
+ raise CannotProcessRequest("Cannot create new build due to: {}"
+ .format(err))
+ except InsufficientRightsException as err:
+ raise AccessForbidden("User {} cannon create build in project {}"
+ .format(flask.g.user.username,
+ project.full_name))
+
+ return build.id
+
+ @rest_api_auth_required
+ def post(self):
+
+ req = flask.request
+ if "application/json" in req.content_type:
+ build_id = self.handle_post_json(req)
+ elif "multipart/form-data" in req.content_type :
+ build_id = self.handle_post_multipart(req)
+ else:
+ raise MalformedRequest("Got unexpected content type: {}"
+ .format(req.content_type))
+ resp = make_response("", 201)
+ resp.headers["Location"] = url_for(".buildr", build_id=build_id)
+
+ return resp
+
class BuildR(Resource):
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/project.py b/frontend/coprs_frontend/coprs/rest_api/resources/project.py
index 3799ae0..7a3f293 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/project.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/project.py
@@ -16,8 +16,6 @@ from coprs.logic.helpers import slice_query
from coprs.logic.users_logic import UsersLogic
from coprs.logic.coprs_logic import CoprsLogic
from coprs.exceptions import ActionInProgressException, InsufficientRightsException
-from .build import BuildListR
-# from .chroot import CoprChrootListR, CoprChrootR
from coprs.rest_api.schemas import ProjectSchema
from ..exceptions import ObjectAlreadyExists, AuthFailed
from ..util import get_one_safe, json_loads_safe, mm_deserialize, render_allowed_method, mm_serialize_one
diff --git a/frontend/coprs_frontend/coprs/rest_api/schemas.py b/frontend/coprs_frontend/coprs/rest_api/schemas.py
index 0872ee4..057660b 100644
--- a/frontend/coprs_frontend/coprs/rest_api/schemas.py
+++ b/frontend/coprs_frontend/coprs/rest_api/schemas.py
@@ -71,6 +71,7 @@ class BuildChrootSchema(Schema):
started_on = fields.Int(dump_only=True)
ended_on = fields.Int(dump_only=True)
git_hash = fields.Str(dump_only=True)
+ name = fields.Str(dump_only=True)
class BuildSchema(Schema):
@@ -78,23 +79,30 @@ class BuildSchema(Schema):
id = fields.Int(dump_only=True)
state = fields.Str()
- pkgs = fields.Str()
- build_packages = fields.Str()
- pkg_version = fields.Str()
+ pkgs = fields.Str(dump_only=True)
+ build_packages = fields.Str(dump_only=True)
+ pkg_version = fields.Str(dump_only=True)
+
+ repos = SpaceSeparatedList(dump_only=True)
+
+ submitted_on = fields.Int(dump_only=True)
+ started_on = fields.Int(dump_only=True)
+ ended_on = fields.Int(dump_only=True)
+
+ results = fields.Str(dump_only=True)
+ timeout = fields.Int(dump_only=True)
- repos_list = fields.List(fields.Str())
- repos = fields.Str() # todo: replace with SpaceSeparatedList
+ enable_net = fields.Bool(dump_only=True)
- submitted_on = fields.Int()
- started_on = fields.Int()
- ended_on = fields.Int()
+ source_type = fields.Int(dump_only=True)
+ source_json = fields.Str(dump_only=True)
- results = fields.Str()
- timeout = fields.Int()
+class BuildCreateSchema(BuildSchema):
+ project_id = fields.Int(required=True)
+ chroots = fields.List(fields.Str())
enable_net = fields.Bool()
- source_type = fields.Int()
- source_json = fields.Str()
- # owner = fields.Function(lambda b: b.copr.owner.username, dump_only=True)
+class BuildCreateFromUrlSchema(BuildCreateSchema):
+ source_url = fields.Url()
diff --git a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
index 457753b..40ef9bb 100644
--- a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
+++ b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_builds.py
@@ -16,12 +16,13 @@ from coprs import helpers
from coprs.logic import builds_logic
from coprs.logic import coprs_logic
from coprs.logic import packages_logic
+from coprs.logic.builds_logic import BuildsLogic
from coprs.views.misc import login_required, page_not_found
from coprs.views.coprs_ns import coprs_ns
from coprs.exceptions import (ActionInProgressException,
- InsufficientRightsException, MalformedArgumentException)
+ InsufficientRightsException,)
@coprs_ns.route("/build/<int:build_id>/")
@@ -132,50 +133,22 @@ def copr_new_build_upload(username, coprname):
form = forms.BuildFormUploadFactory.create_form_cls(copr.active_chroots)()
if form.validate_on_submit():
- tmp = tempfile.mkdtemp(dir=app.config["SRPM_STORAGE_DIR"])
- tmp_name = os.path.basename(tmp)
- filename = secure_filename(form.pkgs.data.filename)
- file_path = os.path.join(tmp, filename)
- form.pkgs.data.save(file_path)
-
- # make the pkg public
- pkg_url = "https://{hostname}/tmp/{tmp_dir}/{srpm}".format(
- hostname=app.config["PUBLIC_COPR_HOSTNAME"],
- tmp_dir=tmp_name,
- srpm=filename)
-
- # check which chroots we need
- chroots = []
- for chroot in copr.active_chroots:
- if chroot.name in form.selected_chroots:
- chroots.append(chroot)
-
- # create json describing the build source
- source_type = helpers.BuildSourceEnum("srpm_upload")
- source_json = json.dumps({"tmp": tmp_name, "pkg": filename})
-
- # create a new build
- try:
- build = builds_logic.BuildsLogic.add(
- user=flask.g.user,
- pkgs=pkg_url,
- copr=copr,
- chroots=chroots,
- source_type=source_type,
- source_json=source_json,
- enable_net=form.enable_net.data)
-
- if flask.g.user.proven:
- build.memory_reqs = form.memory_reqs.data
- build.timeout = form.timeout.data
+ build_options = {
+ "enable_net": form.enable_net.data,
+ "timeout": form.timeout.data,
+ }
+ try:
+ BuildsLogic.create_new_from_upload(
+ flask.g.user, copr,
+ f_uploader=lambda path: form.pkgs.data.save(path),
+ orig_filename=form.pkgs.data.filename,
+ chroot_names=form.selected_chroots,
+ **build_options
+ )
+ db.session.commit()
except (ActionInProgressException, InsufficientRightsException) as e:
flask.flash(str(e), "error")
- db.session.rollback()
- shutil.rmtree(tmp)
- else:
- flask.flash("New build has been created.")
- db.session.commit()
return flask.redirect(flask.url_for("coprs_ns.copr_builds",
username=username,
@@ -213,7 +186,7 @@ def copr_new_build(username, coprname):
source_type = helpers.BuildSourceEnum("srpm_link")
source_json = json.dumps({"url": pkg})
- build = builds_logic.BuildsLogic.add(
+ build = BuildsLogic.add(
user=flask.g.user,
pkgs=pkg,
copr=copr,
diff --git a/frontend/coprs_frontend/tests/coprs_test_case.py b/frontend/coprs_frontend/tests/coprs_test_case.py
index ca1156c..dedc68b 100644
--- a/frontend/coprs_frontend/tests/coprs_test_case.py
+++ b/frontend/coprs_frontend/tests/coprs_test_case.py
@@ -360,7 +360,11 @@ class CoprsTestCase(object):
created_on=int(time.time()))
self.db.session.add_all([self.a1, self.a2, self.a3])
- def request_rest_api_with_auth(self, url, login=None, token=None, content=None, method="GET"):
+ def request_rest_api_with_auth(self, url,
+ login=None, token=None,
+ content=None, method="GET",
+ headers=None, data=None,
+ content_type="application/json"):
"""
:rtype: flask.wrappers.Response
Requires f_users_api fixture
@@ -370,22 +374,34 @@ class CoprsTestCase(object):
if token is None:
token = self.user_api_creds["user1"]["token"]
- userstring = "{}:{}".format(login, token)
- base64string_user = base64.b64encode(userstring)
- base64string = "Basic " + base64string_user
+ req_headers = {
+ "Authorization": self._get_auth_string(login, token),
+ }
+ if headers:
+ req_headers.update(headers)
kwargs = dict(
method=method,
- content_type="application/json",
- headers={
- "Authorization": base64string
- }
+ content_type=content_type,
+ headers=req_headers,
+ buffered=True,
)
+ if content is not None and data is not None:
+ raise RuntimeError("Don't specify content and data together")
+
if content:
kwargs["data"] = json.dumps(content)
+ if data:
+ kwargs["data"] = data
return self.tc.open(url, **kwargs)
+ def _get_auth_string(self, login, token):
+ userstring = "{}:{}".format(login, token)
+ base64string_user = base64.b64encode(userstring)
+ base64string = "Basic " + base64string_user
+ return base64string
+
class TransactionDecorator(object):
diff --git a/frontend/coprs_frontend/tests/test_api/test_build_chroot_r.py b/frontend/coprs_frontend/tests/test_api/test_build_chroot_r.py
index 6322504..5709b1e 100644
--- a/frontend/coprs_frontend/tests/test_api/test_build_chroot_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_build_chroot_r.py
@@ -48,6 +48,7 @@ class TestBuildChrootResource(CoprsTestCase):
"git_hash",
"started_on",
"ended_on",
+ "name"
]
bc = self.b1_bc[0]
expected_dict = {
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 0885f1b..5aefd36 100644
--- a/frontend/coprs_frontend/tests/test_api/test_build_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_build_r.py
@@ -1,4 +1,5 @@
# coding: utf-8
+from cStringIO import StringIO
import json
from marshmallow import pprint
@@ -6,6 +7,7 @@ import math
import pytest
import sqlalchemy
+from coprs.helpers import BuildSourceEnum
from coprs.logic.users_logic import UsersLogic
from coprs.logic.coprs_logic import CoprsLogic
@@ -108,8 +110,99 @@ class TestBuildResource(CoprsTestCase):
assert builds[:delta] == obj1["builds"]
assert builds[delta:2 * delta] == obj2["builds"]
+ # todo: implement
+ def _test_post_json(
+ self, f_users, f_coprs, f_builds, f_db, f_mock_chroots,
+ f_mock_chroots_many, f_build_many_chroots,
+ f_users_api):
+
+ chroot_name_list = [c.name for c in self.c1.active_chroots]
+ metadata = {
+ "project_id": 1,
+ "url": "http://example.com/mypkg.src.rpm",
+ "chroots": chroot_name_list
+ }
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ content=metadata
+ )
+ print(r0.data)
+ assert r0.status_code == 201
+
+ def test_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):
+ chroot_name_list = [c.name for c in self.c1.active_chroots]
+ metadata = {
+ "project_id": 1,
+ "enable_net": True,
+ "chroots": chroot_name_list
+ }
+ data = {
+ "metadata": json.dumps(metadata),
+ "srpm": (StringIO(u'my file contents'), 'hello world.src.rpm')
+ }
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ content_type="multipart/form-data",
+ data=data
+ )
+ assert r0.status_code == 201
+ r1 = self.tc.get(r0.headers["Location"])
+ assert r1.status_code == 200
+ build_obj = json.loads(r1.data)
+
+ assert build_obj["build"]["source_type"] == BuildSourceEnum("srpm_upload")
+
+ chroots_href = build_obj["_links"]["chroots"]["href"]
+ r2 = self.tc.get(chroots_href)
+ build_chroots_obj = json.loads(r2.data)
+ build_chroots_names = set([bc["chroot"]["name"] for bc in
+ build_chroots_obj["chroots"]])
+ assert set(chroot_name_list) == build_chroots_names
+ assert len(chroot_name_list) == len(build_chroots_obj["chroots"])
+
+ def test_post_multipart_missing_file(
+ self,f_users, f_coprs, f_builds, f_db,
+ f_users_api, f_mock_chroots):
+
+ metadata = {
+ "enable_net": True
+ }
+ data = {
+ "metadata": json.dumps(metadata),
+ }
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ content_type="multipart/form-data",
+ data=data
+ )
+ assert r0.status_code == 400
+
+ def test_post_multipart_missing_metadata(
+ self,f_users, f_coprs, f_builds, f_db,
+ f_users_api, f_mock_chroots):
+ data = {
+ "srpm": (StringIO(u'my file contents'), 'hello world.src.rpm')
+ }
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds",
+ method="post",
+ content_type="multipart/form-data",
+ data=data
+ )
+ assert r0.status_code == 400
+
def test_get_one(self, f_users, f_coprs, f_builds, f_db,
- f_users_api, f_mock_chroots):
+ f_users_api, f_mock_chroots):
build_id_list = [b.id for b in self.basic_builds]
self.db.session.commit()
diff --git a/frontend/coprs_frontend/tests/test_api/test_project_r.py b/frontend/coprs_frontend/tests/test_api/test_project_r.py
index 71e2cc9..902b551 100644
--- a/frontend/coprs_frontend/tests/test_api/test_project_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_project_r.py
@@ -36,6 +36,7 @@ class TestProjectResource(CoprsTestCase):
r = self.request_rest_api_with_auth("/api_2/projects", content=body, method="post")
assert r.status_code == 201
+ # todo: test header Location
copr_dict = json.loads(r.data)
assert copr_dict["copr"]["id"] == 1
r2 = self.tc.get("/api_2/projects/1/chroots")
diff --git a/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py b/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
index 7c88ff9..b99955d 100644
--- a/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
+++ b/frontend/coprs_frontend/tests/test_logic/test_builds_logic.py
@@ -42,7 +42,6 @@ class TestBuildsLogic(CoprsTestCase):
pkgs="blah",
copr=self.c1,
repos="repos",
- memory_reqs=3000,
timeout=5000)
b = BuildsLogic.add(**params)
@@ -57,7 +56,6 @@ class TestBuildsLogic(CoprsTestCase):
pkgs="blah blah",
copr=self.c1,
repos="repos",
- memory_reqs=3000,
timeout=5000)
with pytest.raises(MalformedArgumentException):
8 years, 7 months
[copr] master: [frontend][api] Added tests for Build[List]Resource for the GET method (39d3a1d)
by vgologuz@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit 39d3a1d94c852b8d7711763dd0e3ca7a90e4a115
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Thu Aug 27 14:20:39 2015 +0200
[frontend][api] Added tests for Build[List]Resource for the GET method
>---------------------------------------------------------------
.../coprs/rest_api/resources/build.py | 29 +++---
frontend/coprs_frontend/coprs/rest_api/schemas.py | 2 +-
frontend/coprs_frontend/tests/coprs_test_case.py | 7 +-
.../coprs_frontend/tests/test_api/test_build_r.py | 109 ++++++++++++++++++--
4 files changed, 118 insertions(+), 29 deletions(-)
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/build.py b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
index 01f274e..33fba81 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/build.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/build.py
@@ -16,6 +16,17 @@ from coprs.rest_api.util import get_one_safe
from flask_restful import Resource, reqparse
+def render_build(build):
+ return {
+ "build": BuildSchema().dump(build)[0],
+ "_links": {
+ "self": {"href": url_for(".buildr", build_id=build.id)},
+ "project": {"href": url_for(".projectr", project_id=build.copr_id)},
+ "chroots": {"href": url_for(".buildchrootlistr", build_id=build.id)}
+ }
+ }
+
+
class BuildListR(Resource):
def get(self):
@@ -33,7 +44,7 @@ class BuildListR(Resource):
if req_args["project_id"] is not None:
copr = get_one_safe(CoprsLogic.get_by_id(req_args["project_id"]))
query = BuildsLogic.get_multiple_by_copr(copr)
- elif req_args["owner" ] is not None:
+ elif req_args["owner"] is not None:
user = get_one_safe(UsersLogic.get(req_args["owner"]))
query = BuildsLogic.get_multiple_by_owner(user)
else:
@@ -58,12 +69,7 @@ class BuildListR(Resource):
return {
"builds": [
- {
- "build": BuildSchema().dump(build)[0],
- "_links": {
- "self": {"href": url_for(".buildr", build_id=build.id)},
- }
- } for build in builds
+ render_build(build) for build in builds
],
"_links": {
"self": {"href": url_for(".buildlistr", **self_params)},
@@ -78,14 +84,7 @@ class BuildR(Resource):
build = get_one_safe(BuildsLogic.get(build_id),
"Not found build with id: {}".format(build_id))
- return {
- "build": BuildSchema().dump(build)[0],
- "_links": {
- "self": {"href": url_for(".buildr", build_id=build_id)},
- "project": {"href": url_for(".projectr", project_id=build.copr_id)},
- "chroots": {"href": url_for(".buildchrootlistr", build_id=build_id)}
- }
- }
+ return render_build(build)
# to get build details and cancel individual build chroots
diff --git a/frontend/coprs_frontend/coprs/rest_api/schemas.py b/frontend/coprs_frontend/coprs/rest_api/schemas.py
index 4371f79..0872ee4 100644
--- a/frontend/coprs_frontend/coprs/rest_api/schemas.py
+++ b/frontend/coprs_frontend/coprs/rest_api/schemas.py
@@ -75,7 +75,7 @@ class BuildChrootSchema(Schema):
class BuildSchema(Schema):
- id = fields.Int()
+ id = fields.Int(dump_only=True)
state = fields.Str()
pkgs = fields.Str()
diff --git a/frontend/coprs_frontend/tests/coprs_test_case.py b/frontend/coprs_frontend/tests/coprs_test_case.py
index 0bee47d..ca1156c 100644
--- a/frontend/coprs_frontend/tests/coprs_test_case.py
+++ b/frontend/coprs_frontend/tests/coprs_test_case.py
@@ -101,7 +101,9 @@ class CoprsTestCase(object):
proven=False,
mail="baz(a)bar.bar")
- self.db.session.add_all([self.u1, self.u2, self.u3])
+ self.basic_user_list = [self.u1, self.u2, self.u3]
+
+ self.db.session.add_all(self.basic_user_list)
@pytest.fixture
def f_users_api(self):
@@ -122,7 +124,8 @@ class CoprsTestCase(object):
self.c2 = models.Copr(name=u"foocopr", owner=self.u2)
self.c3 = models.Copr(name=u"barcopr", owner=self.u2)
- self.db.session.add_all([self.c1, self.c2, self.c3])
+ self.basic_coprs_list = [self.c1, self.c2, self.c3]
+ self.db.session.add_all(self.basic_coprs_list)
@pytest.fixture
def f_mock_chroots(self):
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 52f18fa..0885f1b 100644
--- a/frontend/coprs_frontend/tests/test_api/test_build_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_build_r.py
@@ -2,35 +2,122 @@
import json
from marshmallow import pprint
+import math
import pytest
import sqlalchemy
from coprs.logic.users_logic import UsersLogic
from coprs.logic.coprs_logic import CoprsLogic
+from coprs.logic.builds_logic import BuildsLogic
from tests.coprs_test_case import CoprsTestCase, TransactionDecorator
class TestBuildResource(CoprsTestCase):
+ @staticmethod
+ def extract_build_ids(response_object):
+ return set([
+ b_dict["build"]["id"]
+ for b_dict in response_object["builds"]
+ ])
+
def test_collection_ok(self, f_users, f_coprs, f_builds, f_db,
f_users_api, f_mock_chroots):
- # project_id = self.c1.id
-
- href = "/api_2/builds/chroots"
- expected_len = len(self.basic_builds)
+ href = "/api_2/builds"
self.db.session.commit()
r = self.tc.get(href)
+ assert r.status_code == 200
+ obj = json.loads(r.data)
+
+ # not a pure test, but we test API here
+ builds = BuildsLogic.get_multiple().all()
+ expected_ids = set([b.id for b in builds])
+
+ assert expected_ids == self.extract_build_ids(obj)
+
+ def test_collection_by_owner(self, f_users, f_coprs, f_builds, f_db,
+ f_users_api, f_mock_chroots):
- def test_collection_ok_by_username(
- 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]
+ for user_name in names_list:
+ href = "/api_2/builds?owner={}".format(user_name)
+ self.db.session.commit()
+ r = self.tc.get(href)
+ assert r.status_code == 200
+ obj = json.loads(r.data)
- # project_id = self.c1.id
+ # not a pure test, but we test API here
+ builds = [
+ b for b in BuildsLogic.get_multiple().all()
+ if b.copr.owner.username == user_name
+ ]
+ expected_ids = set([b.id for b in builds])
+ assert expected_ids == self.extract_build_ids(obj)
- href = "/api_2/builds?owner={}".format(self.u1.username)
- expected_len = 2
+ def test_collection_by_project_id(self, f_users, f_coprs, f_builds, f_db,
+ f_users_api, f_mock_chroots):
+
+ project_id_list = [copr.id for copr in self.basic_coprs_list]
+ for id_ in project_id_list:
+ href = "/api_2/builds?project_id={}".format(id_)
+ self.db.session.commit()
+ r = self.tc.get(href)
+ assert r.status_code == 200
+ obj = json.loads(r.data)
+
+ # not a pure test, but we test API here
+ builds = [
+ b for b in BuildsLogic.get_multiple().all()
+ if b.copr.id == id_
+ ]
+ 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):
self.db.session.commit()
- r = self.tc.get(href)
+ builds = BuildsLogic.get_multiple().all()
+ total = len(builds)
+
+ # test limit
+ for lim in range(1, total + 1):
+ href = "/api_2/builds?limit={}".format(lim)
+ r = self.tc.get(href)
+ assert r.status_code == 200
+ obj = json.loads(r.data)
+ builds = obj["builds"]
+ assert len(builds) == lim
+
+ if lim > 2:
+ delta = int(math.floor(lim / 2))
+ href1 = "/api_2/builds?limit={}".format(delta)
+ href2 = "/api_2/builds?limit={0}&offset={0}".format(delta)
+
+ r1 = self.tc.get(href1)
+ r2 = self.tc.get(href2)
+
+ assert r1.status_code == 200
+ assert r2.status_code == 200
+
+ obj1 = json.loads(r1.data)
+ obj2 = json.loads(r2.data)
+
+ assert builds[:delta] == obj1["builds"]
+ assert builds[delta:2 * delta] == obj2["builds"]
+
+ def test_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]
+ self.db.session.commit()
+
+ for b_id in build_id_list:
+ href = "/api_2/builds/{}".format(b_id)
+ r = self.tc.get(href)
+ assert r.status_code == 200
+ obj = json.loads(r.data)
+ assert obj["build"]["id"] == b_id
+ assert obj["_links"]["self"]["href"] == href
8 years, 7 months
[copr] master: [frontend][api] Updated and added tests for BuildChroot resource (ed6d74e)
by vgologuz@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit ed6d74ef21a1de107382cb356713afb5f8142b1c
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Wed Aug 26 16:02:13 2015 +0200
[frontend][api] Updated and added tests for BuildChroot resource
>---------------------------------------------------------------
.../coprs_frontend/coprs/logic/builds_logic.py | 19 ++++-
.../coprs/rest_api/resources/build_chroot.py | 68 +++++++++------
frontend/coprs_frontend/coprs/rest_api/schemas.py | 6 +-
frontend/coprs_frontend/tests/coprs_test_case.py | 1 +
.../tests/test_api/test_build_chroot_r.py | 91 ++++++++++++++++++++
.../coprs_frontend/tests/test_api/test_build_r.py | 36 ++++++++
.../tests/test_api/test_mock_chroot_r.py | 9 +--
7 files changed, 194 insertions(+), 36 deletions(-)
diff --git a/frontend/coprs_frontend/coprs/logic/builds_logic.py b/frontend/coprs_frontend/coprs/logic/builds_logic.py
index be28dbd..0369205 100644
--- a/frontend/coprs_frontend/coprs/logic/builds_logic.py
+++ b/frontend/coprs_frontend/coprs/logic/builds_logic.py
@@ -7,6 +7,7 @@ import pprint
import time
from sqlalchemy import or_
from sqlalchemy import and_
+from sqlalchemy.orm.exc import NoResultFound
from sqlalchemy.sql import false
from coprs import app
@@ -15,12 +16,15 @@ from coprs import exceptions
from coprs import models
from coprs import helpers
from coprs.constants import DEFAULT_BUILD_TIMEOUT, MAX_BUILD_TIMEOUT
+from coprs.exceptions import MalformedArgumentException
from coprs.helpers import StatusEnum
from coprs.logic import coprs_logic
from coprs.logic import users_logic
from coprs.logic import packages_logic
from coprs.logic.actions_logic import ActionsLogic
+from coprs.models import BuildChroot
+from .coprs_logic import MockChrootsLogic
log = app.logger
@@ -382,6 +386,18 @@ class BuildsLogic(object):
return None
+class BuildChrootsLogic(object):
+ @classmethod
+ def get_by_build_id_and_name(cls, build_id, name):
+ mc = MockChrootsLogic.get_from_name(name).one()
+
+ return (
+ BuildChroot.query
+ .filter(BuildChroot.build_id == build_id)
+ .filter(BuildChroot.mock_chroot_id == mc.id)
+ )
+
+
class BuildsMonitorLogic(object):
@classmethod
def get_monitor_data(cls, copr):
@@ -390,7 +406,8 @@ class BuildsMonitorLogic(object):
for pkg in copr_packages:
chroots = {}
for ch in copr.active_chroots:
- query = (models.BuildChroot.query.join(models.Build)
+ query = (
+ models.BuildChroot.query.join(models.Build)
.filter(models.Build.package_id == pkg.id)
.filter(models.BuildChroot.mock_chroot_id == ch.id)
.filter(models.BuildChroot.status != helpers.StatusEnum("canceled")))
diff --git a/frontend/coprs_frontend/coprs/rest_api/resources/build_chroot.py b/frontend/coprs_frontend/coprs/rest_api/resources/build_chroot.py
index 9baf263..751ecaa 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/build_chroot.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/build_chroot.py
@@ -6,7 +6,11 @@ from flask import url_for
from flask_restful import Resource, reqparse
from marshmallow import Schema, fields, pprint
-from coprs.logic.builds_logic import BuildsLogic
+
+from ... import models
+from coprs.exceptions import MalformedArgumentException
+from coprs.logic.builds_logic import BuildsLogic, BuildChrootsLogic
+from coprs.rest_api.exceptions import MalformedRequest
from coprs.rest_api.schemas import MockChrootSchema, CoprChrootSchema, BuildChrootSchema
from coprs.views.misc import api_login_required
@@ -15,23 +19,31 @@ from coprs.logic.coprs_logic import MockChrootsLogic, CoprChrootsLogic, CoprsLog
from ..util import get_one_safe, json_loads_safe, mm_deserialize, mm_serialize_one
+def render_build_chroot(chroot):
+ """
+ :type chroot: models.BuildChroot
+ """
+ return {
+ "chroot": mm_serialize_one(BuildChrootSchema, chroot),
+ "_links": {
+ "project": {"href": url_for(".projectr", project_id=chroot.build.copr_id)},
+ "self": {"href": url_for(".buildchrootr",
+ build_id=chroot.build.id,
+ name=chroot.name)},
+ }
+ }
+
+
class BuildChrootListR(Resource):
def get(self, build_id):
build = get_one_safe(BuildsLogic.get(build_id),
- "Not found build with id: {}".format(build_id))
+ "Build {} Not found".format(build_id))
return {
"chroots": [
- {
- "chroot": mm_serialize_one(BuildChrootSchema, chroot),
- "_links": {
- "project": {"href": url_for(".projectr", project_id=build.copr_id)},
- "self": {"href": url_for(".buildchrootr",
- build_id=build.id,
- name=chroot.name)},
- }
- } for chroot in build.build_chroots
- ],
+ render_build_chroot(chroot)
+ for chroot in build.build_chroots
+ ],
"_links": {
"self": {"href": url_for(".buildchrootlistr", build_id=build_id)}
}
@@ -39,17 +51,21 @@ class BuildChrootListR(Resource):
class BuildChrootR(Resource):
- pass
- # def get(self, project_id, name):
- # copr = get_one_safe(CoprsLogic.get_by_id(int(project_id)))
- # chroot = CoprChrootsLogic.get_by_name_safe(copr, name)
- #
- # return {
- # "chroot": mm_serialize_one(CoprChrootSchema, chroot),
- # "_links": {
- # "project": {"href": url_for(".projectr", project_id=copr.id)},
- # "self": {"href": url_for(".projectchrootr",
- # project_id=project_id,
- # name=chroot.name)},
- # }
- # }
+
+ @staticmethod
+ def _get_chroot_safe(build_id, name):
+ try:
+ chroot = get_one_safe(
+ BuildChrootsLogic.get_by_build_id_and_name(build_id, name),
+ "Build chroot {} for build {} not found"
+ )
+ except MalformedArgumentException as err:
+ raise MalformedRequest("Bad mock chroot name: {}".format(err))
+ return chroot
+
+ def get(self, build_id, name):
+ chroot = self._get_chroot_safe(build_id, name)
+ return render_build_chroot(chroot)
+
+ # todo: add put method: allows only to pass status: cancelled to cancel build
+
diff --git a/frontend/coprs_frontend/coprs/rest_api/schemas.py b/frontend/coprs_frontend/coprs/rest_api/schemas.py
index 160ef14..4371f79 100644
--- a/frontend/coprs_frontend/coprs/rest_api/schemas.py
+++ b/frontend/coprs_frontend/coprs/rest_api/schemas.py
@@ -76,12 +76,14 @@ class BuildChrootSchema(Schema):
class BuildSchema(Schema):
id = fields.Int()
+ state = fields.Str()
+
pkgs = fields.Str()
build_packages = fields.Str()
pkg_version = fields.Str()
repos_list = fields.List(fields.Str())
- repos = fields.Str() # legacy
+ repos = fields.Str() # todo: replace with SpaceSeparatedList
submitted_on = fields.Int()
started_on = fields.Int()
@@ -94,3 +96,5 @@ class BuildSchema(Schema):
source_type = fields.Int()
source_json = fields.Str()
+
+ # owner = fields.Function(lambda b: b.copr.owner.username, dump_only=True)
diff --git a/frontend/coprs_frontend/tests/coprs_test_case.py b/frontend/coprs_frontend/tests/coprs_test_case.py
index 52fceb2..0bee47d 100644
--- a/frontend/coprs_frontend/tests/coprs_test_case.py
+++ b/frontend/coprs_frontend/tests/coprs_test_case.py
@@ -205,6 +205,7 @@ class CoprsTestCase(object):
self.b4 = models.Build(
copr=self.c2, package=self.p2, user=self.u2, submitted_on=100)
+ self.basic_builds = [self.b1, self.b2, self.b3, self.b4]
self.b1_bc = []
self.b2_bc = []
self.b3_bc = []
diff --git a/frontend/coprs_frontend/tests/test_api/test_build_chroot_r.py b/frontend/coprs_frontend/tests/test_api/test_build_chroot_r.py
new file mode 100644
index 0000000..6322504
--- /dev/null
+++ b/frontend/coprs_frontend/tests/test_api/test_build_chroot_r.py
@@ -0,0 +1,91 @@
+# coding: utf-8
+import copy
+
+import json
+from marshmallow import pprint
+
+import pytest
+import sqlalchemy
+
+from coprs.logic.users_logic import UsersLogic
+from coprs.logic.coprs_logic import CoprsLogic
+
+from tests.coprs_test_case import CoprsTestCase, TransactionDecorator
+
+
+class TestBuildChrootResource(CoprsTestCase):
+
+ def test_collection_ok(self, f_users, f_coprs, f_mock_chroots, f_builds, f_db,
+ f_users_api):
+
+ # project_id = self.c1.id
+ # import ipdb; ipdb.set_trace()
+ href = "/api_2/builds/1/chroots"
+ bc_list = copy.deepcopy(self.b1_bc)
+
+ self.db.session.commit()
+
+ r0 = self.tc.get(href)
+ assert r0.status_code == 200
+ obj = json.loads(r0.data)
+ assert len(obj["chroots"]) == len(bc_list)
+ assert obj["_links"]["self"]["href"] == href
+
+ def test_post_not_allowed(self, f_users, f_coprs, f_mock_chroots, f_builds, f_db,
+ f_users_api):
+ self.db.session.commit()
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/builds/1/chroots",
+ method="post",
+ content={},
+ )
+ assert r0.status_code == 405
+
+ def test_get_one(self, f_users, f_coprs, f_mock_chroots, f_builds, f_db,
+ f_users_api):
+ expected_fields = [
+ "state",
+ "git_hash",
+ "started_on",
+ "ended_on",
+ ]
+ bc = self.b1_bc[0]
+ expected_dict = {
+ f: getattr(bc, f)
+ for f in expected_fields
+ }
+ href = "/api_2/builds/1/chroots/{}".format(bc.name)
+ self.db.session.commit()
+
+ r0 = self.tc.get(href)
+ assert r0.status_code == 200
+ obj = json.loads(r0.data)
+ assert obj["chroot"] == expected_dict
+
+ def test_get_one_bad_name(self, f_users, f_coprs, f_mock_chroots, f_builds, f_db,
+ f_users_api):
+
+ href = "/api_2/builds/1/chroots/surely_bad_chroot_name"
+ self.db.session.commit()
+
+ r0 = self.tc.get(href)
+ assert r0.status_code == 400
+
+ def get_test_not_found(
+ self, f_users, f_coprs, f_mock_chroots, f_builds, f_db, f_users_api):
+
+ bc = self.b1_bc[0]
+ href = "/api_2/builds/48545656/chroots/{}".format(bc.name)
+ href2 = "/api_2/builds/1/chroots/{}".format(bc.name)
+ self.db.session.commit()
+
+ r0 = self.tc.get(href)
+ assert r0.status_code == 404
+
+ r1 = self.tc.get(href2)
+ assert r1.status_code == 404
+
+
+ # def test_put_cancel_build_chroot
+
+
diff --git a/frontend/coprs_frontend/tests/test_api/test_build_r.py b/frontend/coprs_frontend/tests/test_api/test_build_r.py
new file mode 100644
index 0000000..52f18fa
--- /dev/null
+++ b/frontend/coprs_frontend/tests/test_api/test_build_r.py
@@ -0,0 +1,36 @@
+# coding: utf-8
+
+import json
+from marshmallow import pprint
+
+import pytest
+import sqlalchemy
+
+from coprs.logic.users_logic import UsersLogic
+from coprs.logic.coprs_logic import CoprsLogic
+
+from tests.coprs_test_case import CoprsTestCase, TransactionDecorator
+
+
+class TestBuildResource(CoprsTestCase):
+
+ def test_collection_ok(self, f_users, f_coprs, f_builds, f_db,
+ f_users_api, f_mock_chroots):
+
+ # project_id = self.c1.id
+
+ href = "/api_2/builds/chroots"
+ expected_len = len(self.basic_builds)
+ self.db.session.commit()
+ r = self.tc.get(href)
+
+ def test_collection_ok_by_username(
+ self, f_users, f_coprs, f_builds, f_db,
+ f_users_api, f_mock_chroots):
+
+ # project_id = self.c1.id
+
+ href = "/api_2/builds?owner={}".format(self.u1.username)
+ expected_len = 2
+ self.db.session.commit()
+ r = self.tc.get(href)
diff --git a/frontend/coprs_frontend/tests/test_api/test_mock_chroot_r.py b/frontend/coprs_frontend/tests/test_api/test_mock_chroot_r.py
index 3c4061c..beb3568 100644
--- a/frontend/coprs_frontend/tests/test_api/test_mock_chroot_r.py
+++ b/frontend/coprs_frontend/tests/test_api/test_mock_chroot_r.py
@@ -36,17 +36,10 @@ class TestMockChrootResource(CoprsTestCase):
assert len(obj["chroots"]) == expected_len
def test_post_not_allowed(self, f_mock_chroots, f_db, f_users, f_users_api):
- data = {
- u'arch': u'i386',
- u'is_active': True,
- u'name': u'fedora-99-i386',
- u'os_release': u'fedora',
- u'os_version': u'99'
- }
r0 = self.request_rest_api_with_auth(
"/api_2/mock_chroots",
method="post",
- content=data,
+ content={},
)
assert r0.status_code == 405
8 years, 7 months
[copr] master: [frontend][api] update MockChroot Resource, covered with tests (c726d16)
by vgologuz@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit c726d16b20e8daeb56b159521721877ac05c58c1
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Wed Aug 26 14:21:59 2015 +0200
[frontend][api] update MockChroot Resource, covered with tests
>---------------------------------------------------------------
.../coprs/rest_api/resources/mock_chroot.py | 44 +++++++++------
frontend/coprs_frontend/tests/coprs_test_case.py | 1 +
.../tests/test_api/test_mock_chroot_r.py | 60 ++++++++++++++++++++
..._project_chroot.py => test_project_chroot_r.py} | 0
4 files changed, 88 insertions(+), 17 deletions(-)
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 0ffa083..0ee1d0d 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/mock_chroot.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/mock_chroot.py
@@ -14,21 +14,38 @@ from coprs.logic.coprs_logic import MockChrootsLogic, CoprChrootsLogic, CoprsLog
from ..util import get_one_safe, json_loads_safe, mm_deserialize
+def render_mock_chroot(chroot):
+ return {
+ "chroot": MockChrootSchema().dump(chroot)[0],
+ "_links": {
+ "self": {"href": url_for(".mockchrootr", name=chroot.name)},
+ "all_chroots": {"href": url_for(".mockchrootlistr")}
+ },
+ }
+
+
class MockChrootListR(Resource):
+
def get(self):
- # todo: add argument active_only
- chroots = MockChrootsLogic.get_multiple(active_only=False).all()
+ parser = reqparse.RequestParser()
+ parser.add_argument('active_only', type=bool)
+ req_args = parser.parse_args()
+ active_only = False
+ if req_args["active_only"]:
+ active_only = True
+
+ chroots = MockChrootsLogic.get_multiple(active_only=active_only).all()
+
+ self_extra = {}
+ if active_only:
+ self_extra["active_only"] = active_only
return {
"_links": {
- "self": {"href": url_for(".mockchrootlistr")},
+ "self": {"href": url_for(".mockchrootlistr", **self_extra)},
},
"chroots": [
- {
- "chroot": MockChrootSchema().dump(chroot)[0],
- "_links": {
- "self": {"href": url_for(".mockchrootr", name=chroot.name)},
- }
- } for chroot in chroots
+ render_mock_chroot(chroot)
+ for chroot in chroots
]
}
@@ -36,11 +53,4 @@ class MockChrootListR(Resource):
class MockChrootR(Resource):
def get(self, name):
chroot = get_one_safe(MockChrootsLogic.get_from_name(name))
- return {
- "chroot": MockChrootSchema().dump(chroot)[0],
- "_links": {
- "self": {"href": url_for(".mockchrootr", name=chroot.name)},
- "all_chroots": {"href": url_for(".mockchrootlistr")}
- },
- }
-
+ return render_mock_chroot(chroot)
diff --git a/frontend/coprs_frontend/tests/coprs_test_case.py b/frontend/coprs_frontend/tests/coprs_test_case.py
index 37db540..52fceb2 100644
--- a/frontend/coprs_frontend/tests/coprs_test_case.py
+++ b/frontend/coprs_frontend/tests/coprs_test_case.py
@@ -135,6 +135,7 @@ class CoprsTestCase(object):
self.mc4 = models.MockChroot(
os_release="fedora", os_version="rawhide", arch="i386", is_active=True)
+ self.mc_basic_list = [self.mc1, self.mc2, self.mc3, self.mc4]
# only bind to coprs if the test has used the f_coprs fixture
if hasattr(self, "c1"):
cc1 = models.CoprChroot()
diff --git a/frontend/coprs_frontend/tests/test_api/test_mock_chroot_r.py b/frontend/coprs_frontend/tests/test_api/test_mock_chroot_r.py
new file mode 100644
index 0000000..3c4061c
--- /dev/null
+++ b/frontend/coprs_frontend/tests/test_api/test_mock_chroot_r.py
@@ -0,0 +1,60 @@
+# coding: utf-8
+
+import json
+from marshmallow import pprint
+
+import pytest
+import sqlalchemy
+
+from coprs.logic.users_logic import UsersLogic
+from coprs.logic.coprs_logic import CoprsLogic
+
+from tests.coprs_test_case import CoprsTestCase, TransactionDecorator
+
+
+class TestMockChrootResource(CoprsTestCase):
+
+ def test_collection(self, f_mock_chroots, f_db):
+ href = "/api_2/mock_chroots"
+ r = self.tc.get(href)
+ assert r.status_code == 200
+ obj = json.loads(r.data)
+ assert obj["_links"]["self"]["href"] == href
+ assert len(obj["chroots"]) == len(self.mc_basic_list)
+
+ def test_collection_only_active(self, f_mock_chroots, f_db):
+ expected_len = len(self.mc_basic_list) - 1
+ self.mc4.is_active = False
+ self.db.session.add(self.mc4)
+ self.db.session.commit()
+
+ href = "/api_2/mock_chroots?active_only=True"
+ r = self.tc.get(href)
+ assert r.status_code == 200
+ obj = json.loads(r.data)
+ assert obj["_links"]["self"]["href"] == href
+ assert len(obj["chroots"]) == expected_len
+
+ def test_post_not_allowed(self, f_mock_chroots, f_db, f_users, f_users_api):
+ data = {
+ u'arch': u'i386',
+ u'is_active': True,
+ u'name': u'fedora-99-i386',
+ u'os_release': u'fedora',
+ u'os_version': u'99'
+ }
+ r0 = self.request_rest_api_with_auth(
+ "/api_2/mock_chroots",
+ method="post",
+ content=data,
+ )
+ assert r0.status_code == 405
+
+ def test_get_one(self, f_mock_chroots, f_db):
+ chroot_name = self.mc1.name
+ href = "/api_2/mock_chroots/{}".format(chroot_name)
+ r = self.tc.get(href)
+ assert r.status_code == 200
+ obj = json.loads(r.data)
+ assert obj["_links"]["self"]["href"] == href
+ assert obj["chroot"]["name"] == chroot_name
diff --git a/frontend/coprs_frontend/tests/test_api/test_project_chroot.py b/frontend/coprs_frontend/tests/test_api/test_project_chroot_r.py
similarity index 100%
rename from frontend/coprs_frontend/tests/test_api/test_project_chroot.py
rename to frontend/coprs_frontend/tests/test_api/test_project_chroot_r.py
8 years, 7 months
[copr] master: [frontend][api] require marshmallow >= 2; minor test update (32c392c)
by vgologuz@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit 32c392cbfecf6574910d948132ae831ff3ec3713
Author: Valentin Gologuzov <vgologuz(a)redhat.com>
Date: Wed Aug 26 13:38:14 2015 +0200
[frontend][api] require marshmallow >= 2; minor test update
>---------------------------------------------------------------
frontend/copr-frontend.spec | 4 ++--
.../coprs/rest_api/resources/project_chroot.py | 5 +++--
frontend/coprs_frontend/coprs/rest_api/util.py | 4 ++--
.../tests/test_api/test_project_chroot.py | 9 +++++++++
4 files changed, 16 insertions(+), 6 deletions(-)
diff --git a/frontend/copr-frontend.spec b/frontend/copr-frontend.spec
index def204d..4a6b670 100644
--- a/frontend/copr-frontend.spec
+++ b/frontend/copr-frontend.spec
@@ -54,7 +54,7 @@ Requires: pytz
Requires: python-six
Requires: python-netaddr
Requires: python-flask-restful
-Requires: python-marshmallow
+Requires: python-marshmallow >= 2.0.0
# for tests:
Requires: pytest
Requires: python-flexmock
@@ -88,7 +88,7 @@ BuildRequires: python-decorator
BuildRequires: python-markdown
BuildRequires: pytz
BuildRequires: python-flask-restful
-BuildRequires: python-marshmallow
+BuildRequires: python-marshmallow >= 2.0.0
%description
COPR is lightweight build system. It allows you to create new project in WebUI,
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 8958b96..6e03ee1 100644
--- a/frontend/coprs_frontend/coprs/rest_api/resources/project_chroot.py
+++ b/frontend/coprs_frontend/coprs/rest_api/resources/project_chroot.py
@@ -1,6 +1,9 @@
# coding: utf-8
import json
+import logging
+log = logging.getLogger(__name__)
+
import flask
from flask import url_for, make_response
from flask_restful import Resource, reqparse
@@ -121,8 +124,6 @@ class ProjectChrootR(Resource):
chroot = self._get_chroot_safe(copr, name)
chroot_data = mm_deserialize(CoprChrootSchema(), flask.request.data)
- if "name" in chroot_data.data:
- chroot_data.data.pop("name") # todo: why it's here? bug in marshmallow?
try:
updated_chroot = CoprChrootsLogic.update_chroot(
user=flask.g.user,
diff --git a/frontend/coprs_frontend/coprs/rest_api/util.py b/frontend/coprs_frontend/coprs/rest_api/util.py
index c74b2cb..a7e77b6 100644
--- a/frontend/coprs_frontend/coprs/rest_api/util.py
+++ b/frontend/coprs_frontend/coprs/rest_api/util.py
@@ -34,8 +34,8 @@ def json_loads_safe(raw, data_on_error=None):
"Failed to deserialize json string")
-def mm_deserialize(schema, obj_dict):
- result = schema.loads(obj_dict)
+def mm_deserialize(schema, json_string):
+ result = schema.loads(json_string)
if result.errors:
raise MalformedRequest(data="Failed to parse request: {}"
.format(result.errors))
diff --git a/frontend/coprs_frontend/tests/test_api/test_project_chroot.py b/frontend/coprs_frontend/tests/test_api/test_project_chroot.py
index d28b892..3f84822 100644
--- a/frontend/coprs_frontend/tests/test_api/test_project_chroot.py
+++ b/frontend/coprs_frontend/tests/test_api/test_project_chroot.py
@@ -103,6 +103,15 @@ class TestProjectChrootResource(CoprsTestCase):
assert r3.status_code == 200
assert_content(json.loads(r3.data)["chroot"])
+ # test put with excessive name field
+ data["name"] = chroot_name
+ r4 = self.request_rest_api_with_auth(
+ "/api_2/projects/1/chroots/{}".format(chroot_name),
+ method="put",
+ content=data
+ )
+ assert r4.status_code == 200
+
def test_put_erasing(self, f_users, f_coprs, f_db, f_users_api, f_mock_chroots):
chroot_name = self.mc1.name
self.db.session.commit()
8 years, 7 months
[copr] master: typo (9a9aba4)
by asamalik@fedoraproject.org
Repository : http://git.fedorahosted.org/cgit/copr.git
On branch : master
>---------------------------------------------------------------
commit 9a9aba44125210e0420fdb1fe61e3917cc74c719
Author: Adam Samalik <asamalik(a)redhat.com>
Date: Wed Aug 26 12:19:24 2015 +0200
typo
>---------------------------------------------------------------
.../coprs/views/coprs_ns/coprs_general.py | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_general.py b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_general.py
index dd299dc..5a85b87 100644
--- a/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_general.py
+++ b/frontend/coprs_frontend/coprs/views/coprs_ns/coprs_general.py
@@ -155,7 +155,7 @@ def copr_new(username):
)
db.session.commit()
- flask.flash("New project has ben created successfully.", "success")
+ flask.flash("New project has been created successfully.", "success")
if form.initial_pkgs.data:
pkgs = form.initial_pkgs.data.replace("\n", " ").split(" ")
8 years, 7 months