Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / tests / projects.py @ 5d3a191e

History | View | Annotate | Download (33.2 kB)

1 bd1f667b Giorgos Korfiatis
# Copyright 2011, 2012, 2013 GRNET S.A. All rights reserved.
2 1ac3349d Kostas Papadimitriou
#
3 1ac3349d Kostas Papadimitriou
# Redistribution and use in source and binary forms, with or
4 1ac3349d Kostas Papadimitriou
# without modification, are permitted provided that the following
5 1ac3349d Kostas Papadimitriou
# conditions are met:
6 1ac3349d Kostas Papadimitriou
#
7 1ac3349d Kostas Papadimitriou
#   1. Redistributions of source code must retain the above
8 1ac3349d Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
9 1ac3349d Kostas Papadimitriou
#      disclaimer.
10 1ac3349d Kostas Papadimitriou
#
11 1ac3349d Kostas Papadimitriou
#   2. Redistributions in binary form must reproduce the above
12 1ac3349d Kostas Papadimitriou
#      copyright notice, this list of conditions and the following
13 1ac3349d Kostas Papadimitriou
#      disclaimer in the documentation and/or other materials
14 1ac3349d Kostas Papadimitriou
#      provided with the distribution.
15 1ac3349d Kostas Papadimitriou
#
16 1ac3349d Kostas Papadimitriou
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17 1ac3349d Kostas Papadimitriou
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 1ac3349d Kostas Papadimitriou
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 1ac3349d Kostas Papadimitriou
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20 1ac3349d Kostas Papadimitriou
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 1ac3349d Kostas Papadimitriou
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 1ac3349d Kostas Papadimitriou
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23 1ac3349d Kostas Papadimitriou
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24 1ac3349d Kostas Papadimitriou
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 1ac3349d Kostas Papadimitriou
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26 1ac3349d Kostas Papadimitriou
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 1ac3349d Kostas Papadimitriou
# POSSIBILITY OF SUCH DAMAGE.
28 1ac3349d Kostas Papadimitriou
#
29 1ac3349d Kostas Papadimitriou
# The views and conclusions contained in the software and
30 1ac3349d Kostas Papadimitriou
# documentation are those of the authors and should not be
31 1ac3349d Kostas Papadimitriou
# interpreted as representing official policies, either expressed
32 1ac3349d Kostas Papadimitriou
# or implied, of GRNET S.A.
33 1ac3349d Kostas Papadimitriou
34 1ac3349d Kostas Papadimitriou
from astakos.im.tests.common import *
35 2556cf45 Giorgos Korfiatis
36 2556cf45 Giorgos Korfiatis
37 2070c5f8 Giorgos Korfiatis
NotFound = type('NotFound', (), {})
38 2070c5f8 Giorgos Korfiatis
39 2070c5f8 Giorgos Korfiatis
40 2070c5f8 Giorgos Korfiatis
def find(f, seq):
41 2070c5f8 Giorgos Korfiatis
    for item in seq:
42 2070c5f8 Giorgos Korfiatis
        if f(item):
43 2070c5f8 Giorgos Korfiatis
            return item
44 2070c5f8 Giorgos Korfiatis
    return NotFound
45 2070c5f8 Giorgos Korfiatis
46 2070c5f8 Giorgos Korfiatis
47 2556cf45 Giorgos Korfiatis
class ProjectAPITest(TestCase):
48 2556cf45 Giorgos Korfiatis
49 2556cf45 Giorgos Korfiatis
    def setUp(self):
50 2556cf45 Giorgos Korfiatis
        self.client = Client()
51 2556cf45 Giorgos Korfiatis
        component1 = Component.objects.create(name="comp1")
52 2556cf45 Giorgos Korfiatis
        register.add_service(component1, "service1", "type1", [])
53 2556cf45 Giorgos Korfiatis
        # custom service resources
54 2556cf45 Giorgos Korfiatis
        resource11 = {"name": "service1.resource11",
55 2556cf45 Giorgos Korfiatis
                      "desc": "resource11 desc",
56 2556cf45 Giorgos Korfiatis
                      "service_type": "type1",
57 2556cf45 Giorgos Korfiatis
                      "service_origin": "service1",
58 2dc27ac1 Giorgos Korfiatis
                      "ui_visible": True}
59 2556cf45 Giorgos Korfiatis
        r, _ = register.add_resource(resource11)
60 2070c5f8 Giorgos Korfiatis
        register.update_base_default(r, 100)
61 2556cf45 Giorgos Korfiatis
        resource12 = {"name": "service1.resource12",
62 2556cf45 Giorgos Korfiatis
                      "desc": "resource11 desc",
63 2556cf45 Giorgos Korfiatis
                      "service_type": "type1",
64 2556cf45 Giorgos Korfiatis
                      "service_origin": "service1",
65 2556cf45 Giorgos Korfiatis
                      "unit": "bytes"}
66 2556cf45 Giorgos Korfiatis
        r, _ = register.add_resource(resource12)
67 2070c5f8 Giorgos Korfiatis
        register.update_base_default(r, 1024)
68 2556cf45 Giorgos Korfiatis
69 2556cf45 Giorgos Korfiatis
        # create user
70 1808f7bc Giorgos Korfiatis
        self.user1 = get_local_user("test@grnet.gr")
71 1808f7bc Giorgos Korfiatis
        self.user2 = get_local_user("test2@grnet.gr")
72 2556cf45 Giorgos Korfiatis
        self.user2.uuid = "uuid2"
73 2556cf45 Giorgos Korfiatis
        self.user2.save()
74 1808f7bc Giorgos Korfiatis
        self.user3 = get_local_user("test3@grnet.gr")
75 2556cf45 Giorgos Korfiatis
76 2556cf45 Giorgos Korfiatis
        astakos = Component.objects.create(name="astakos")
77 2556cf45 Giorgos Korfiatis
        register.add_service(astakos, "astakos_account", "account", [])
78 2556cf45 Giorgos Korfiatis
        # create another service
79 2556cf45 Giorgos Korfiatis
        pending_app = {"name": "astakos.pending_app",
80 2556cf45 Giorgos Korfiatis
                       "desc": "pend app desc",
81 2556cf45 Giorgos Korfiatis
                       "service_type": "account",
82 2556cf45 Giorgos Korfiatis
                       "service_origin": "astakos_account",
83 2dc27ac1 Giorgos Korfiatis
                       "ui_visible": False,
84 2dc27ac1 Giorgos Korfiatis
                       "api_visible": False}
85 2556cf45 Giorgos Korfiatis
        r, _ = register.add_resource(pending_app)
86 2070c5f8 Giorgos Korfiatis
        register.update_base_default(r, 3)
87 2070c5f8 Giorgos Korfiatis
        request = {"resources": {r.name: {"member_capacity": 3,
88 2070c5f8 Giorgos Korfiatis
                                          "project_capacity": 3}}}
89 2070c5f8 Giorgos Korfiatis
        functions.modify_projects_in_bulk(Q(is_base=True), request)
90 2556cf45 Giorgos Korfiatis
91 2556cf45 Giorgos Korfiatis
    def create(self, app, headers):
92 2556cf45 Giorgos Korfiatis
        dump = json.dumps(app)
93 2556cf45 Giorgos Korfiatis
        r = self.client.post(reverse("api_projects"), dump,
94 2556cf45 Giorgos Korfiatis
                             content_type="application/json", **headers)
95 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
96 2556cf45 Giorgos Korfiatis
        return r.status_code, body
97 2556cf45 Giorgos Korfiatis
98 2556cf45 Giorgos Korfiatis
    def modify(self, app, project_id, headers):
99 2556cf45 Giorgos Korfiatis
        dump = json.dumps(app)
100 2556cf45 Giorgos Korfiatis
        kwargs = {"project_id": project_id}
101 d9fca80b Giorgos Korfiatis
        r = self.client.put(reverse("api_project", kwargs=kwargs), dump,
102 2556cf45 Giorgos Korfiatis
                             content_type="application/json", **headers)
103 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
104 2556cf45 Giorgos Korfiatis
        return r.status_code, body
105 2556cf45 Giorgos Korfiatis
106 2070c5f8 Giorgos Korfiatis
    def project_action(self, project_id, action, app_id=None, headers=None):
107 2070c5f8 Giorgos Korfiatis
        action_data = {"reason": ""}
108 2070c5f8 Giorgos Korfiatis
        if app_id is not None:
109 2070c5f8 Giorgos Korfiatis
            action_data["app_id"] = app_id
110 2070c5f8 Giorgos Korfiatis
        action = json.dumps({action: action_data})
111 2556cf45 Giorgos Korfiatis
        r = self.client.post(reverse("api_project_action",
112 2556cf45 Giorgos Korfiatis
                                     kwargs={"project_id": project_id}),
113 2556cf45 Giorgos Korfiatis
                             action, content_type="application/json",
114 2556cf45 Giorgos Korfiatis
                             **headers)
115 2556cf45 Giorgos Korfiatis
        return r.status_code
116 2556cf45 Giorgos Korfiatis
117 2556cf45 Giorgos Korfiatis
    def memb_action(self, memb_id, action, headers):
118 2556cf45 Giorgos Korfiatis
        action = json.dumps({action: "reason"})
119 2556cf45 Giorgos Korfiatis
        r = self.client.post(reverse("api_membership_action",
120 2556cf45 Giorgos Korfiatis
                                     kwargs={"memb_id": memb_id}), action,
121 2556cf45 Giorgos Korfiatis
                             content_type="application/json", **headers)
122 2556cf45 Giorgos Korfiatis
        return r.status_code
123 2556cf45 Giorgos Korfiatis
124 2556cf45 Giorgos Korfiatis
    def join(self, project_id, headers):
125 2556cf45 Giorgos Korfiatis
        action = {"join": {"project": project_id}}
126 2556cf45 Giorgos Korfiatis
        req = json.dumps(action)
127 2556cf45 Giorgos Korfiatis
        r = self.client.post(reverse("api_memberships"), req,
128 2556cf45 Giorgos Korfiatis
                             content_type="application/json", **headers)
129 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
130 2556cf45 Giorgos Korfiatis
        return r.status_code, body
131 2556cf45 Giorgos Korfiatis
132 2556cf45 Giorgos Korfiatis
    def enroll(self, project_id, user, headers):
133 2556cf45 Giorgos Korfiatis
        action = {
134 2556cf45 Giorgos Korfiatis
            "enroll": {
135 2556cf45 Giorgos Korfiatis
                "project": project_id,
136 2556cf45 Giorgos Korfiatis
                "user": user.email,
137 2556cf45 Giorgos Korfiatis
            }
138 2556cf45 Giorgos Korfiatis
        }
139 2556cf45 Giorgos Korfiatis
        req = json.dumps(action)
140 2556cf45 Giorgos Korfiatis
        r = self.client.post(reverse("api_memberships"), req,
141 2556cf45 Giorgos Korfiatis
                             content_type="application/json", **headers)
142 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
143 2556cf45 Giorgos Korfiatis
        return r.status_code, body
144 2556cf45 Giorgos Korfiatis
145 2556cf45 Giorgos Korfiatis
    @im_settings(PROJECT_ADMINS=["uuid2"])
146 2556cf45 Giorgos Korfiatis
    def test_projects(self):
147 2556cf45 Giorgos Korfiatis
        client = self.client
148 2556cf45 Giorgos Korfiatis
        h_owner = {"HTTP_X_AUTH_TOKEN": self.user1.auth_token}
149 2556cf45 Giorgos Korfiatis
        h_admin = {"HTTP_X_AUTH_TOKEN": self.user2.auth_token}
150 2556cf45 Giorgos Korfiatis
        h_plain = {"HTTP_X_AUTH_TOKEN": self.user3.auth_token}
151 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_project", kwargs={"project_id": 1}))
152 2556cf45 Giorgos Korfiatis
        self.assertEqual(r.status_code, 401)
153 2556cf45 Giorgos Korfiatis
154 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_project", kwargs={"project_id": 1}),
155 2556cf45 Giorgos Korfiatis
                       **h_owner)
156 2556cf45 Giorgos Korfiatis
        self.assertEqual(r.status_code, 404)
157 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_membership", kwargs={"memb_id": 100}),
158 2556cf45 Giorgos Korfiatis
                       **h_owner)
159 2556cf45 Giorgos Korfiatis
        self.assertEqual(r.status_code, 404)
160 2556cf45 Giorgos Korfiatis
161 2556cf45 Giorgos Korfiatis
        status = self.memb_action(1, "accept", h_admin)
162 2070c5f8 Giorgos Korfiatis
        self.assertEqual(status, 409)
163 2556cf45 Giorgos Korfiatis
164 2556cf45 Giorgos Korfiatis
        app1 = {"name": "test.pr",
165 2556cf45 Giorgos Korfiatis
                "end_date": "2013-5-5T20:20:20Z",
166 2556cf45 Giorgos Korfiatis
                "join_policy": "auto",
167 e98239db Giorgos Korfiatis
                "max_members": 5,
168 2556cf45 Giorgos Korfiatis
                "resources": {"service1.resource11": {
169 2070c5f8 Giorgos Korfiatis
                    "project_capacity": 1024,
170 2556cf45 Giorgos Korfiatis
                    "member_capacity": 512}}
171 2556cf45 Giorgos Korfiatis
                }
172 2556cf45 Giorgos Korfiatis
173 2070c5f8 Giorgos Korfiatis
        status, body = self.modify(app1, 100, h_owner)
174 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 404)
175 2556cf45 Giorgos Korfiatis
176 2556cf45 Giorgos Korfiatis
        # Create
177 2556cf45 Giorgos Korfiatis
        status, body = self.create(app1, h_owner)
178 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 201)
179 2556cf45 Giorgos Korfiatis
        project_id = body["id"]
180 2556cf45 Giorgos Korfiatis
        app_id = body["application"]
181 2556cf45 Giorgos Korfiatis
182 2556cf45 Giorgos Korfiatis
        # Get project
183 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_project",
184 2556cf45 Giorgos Korfiatis
                               kwargs={"project_id": project_id}),
185 2556cf45 Giorgos Korfiatis
                       **h_owner)
186 2556cf45 Giorgos Korfiatis
        self.assertEqual(r.status_code, 200)
187 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
188 2556cf45 Giorgos Korfiatis
        self.assertEqual(body["id"], project_id)
189 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["id"], app_id)
190 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["state"], "pending")
191 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["state"], "uninitialized")
192 2556cf45 Giorgos Korfiatis
        self.assertEqual(body["owner"], self.user1.uuid)
193 2556cf45 Giorgos Korfiatis
194 2556cf45 Giorgos Korfiatis
        # Approve forbidden
195 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "approve", app_id=app_id,
196 2070c5f8 Giorgos Korfiatis
                                     headers=h_owner)
197 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 403)
198 2556cf45 Giorgos Korfiatis
199 2556cf45 Giorgos Korfiatis
        # Create another with the same name
200 2556cf45 Giorgos Korfiatis
        status, body = self.create(app1, h_owner)
201 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 201)
202 2556cf45 Giorgos Korfiatis
        project2_id = body["id"]
203 2556cf45 Giorgos Korfiatis
        project2_app_id = body["application"]
204 2556cf45 Giorgos Korfiatis
205 2556cf45 Giorgos Korfiatis
        # Create yet another, with different name
206 2556cf45 Giorgos Korfiatis
        app_p3 = copy.deepcopy(app1)
207 2556cf45 Giorgos Korfiatis
        app_p3["name"] = "new.pr"
208 2556cf45 Giorgos Korfiatis
        status, body = self.create(app_p3, h_owner)
209 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 201)
210 2070c5f8 Giorgos Korfiatis
        project3_id = body["id"]
211 2556cf45 Giorgos Korfiatis
        project3_app_id = body["application"]
212 2556cf45 Giorgos Korfiatis
213 2556cf45 Giorgos Korfiatis
        # No more pending allowed
214 2556cf45 Giorgos Korfiatis
        status, body = self.create(app_p3, h_owner)
215 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 409)
216 2556cf45 Giorgos Korfiatis
217 2556cf45 Giorgos Korfiatis
        # Cancel
218 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project3_id, "cancel",
219 2070c5f8 Giorgos Korfiatis
                                     app_id=project3_app_id, headers=h_owner)
220 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
221 2556cf45 Giorgos Korfiatis
222 2070c5f8 Giorgos Korfiatis
        # Get project
223 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_project",
224 2070c5f8 Giorgos Korfiatis
                               kwargs={"project_id": project3_id}),
225 2070c5f8 Giorgos Korfiatis
                       **h_owner)
226 2070c5f8 Giorgos Korfiatis
        body = json.loads(r.content)
227 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["state"], "deleted")
228 2070c5f8 Giorgos Korfiatis
229 2070c5f8 Giorgos Korfiatis
        # Modify of uninitialized failed
230 2556cf45 Giorgos Korfiatis
        app2 = {"name": "test.pr",
231 2556cf45 Giorgos Korfiatis
                "start_date": "2013-5-5T20:20:20Z",
232 2556cf45 Giorgos Korfiatis
                "end_date": "2013-7-5T20:20:20Z",
233 2556cf45 Giorgos Korfiatis
                "join_policy": "moderated",
234 2556cf45 Giorgos Korfiatis
                "leave_policy": "auto",
235 2556cf45 Giorgos Korfiatis
                "max_members": 3,
236 2556cf45 Giorgos Korfiatis
                "resources": {"service1.resource11": {
237 2070c5f8 Giorgos Korfiatis
                    "project_capacity": 1024,
238 2556cf45 Giorgos Korfiatis
                    "member_capacity": 1024}}
239 2556cf45 Giorgos Korfiatis
                }
240 2556cf45 Giorgos Korfiatis
        status, body = self.modify(app2, project_id, h_owner)
241 2070c5f8 Giorgos Korfiatis
        self.assertEqual(status, 409)
242 2070c5f8 Giorgos Korfiatis
243 2070c5f8 Giorgos Korfiatis
        # Create the project again
244 2070c5f8 Giorgos Korfiatis
        status, body = self.create(app2, h_owner)
245 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 201)
246 2070c5f8 Giorgos Korfiatis
        project_id = body["id"]
247 2070c5f8 Giorgos Korfiatis
        app_id = body["application"]
248 2556cf45 Giorgos Korfiatis
249 2556cf45 Giorgos Korfiatis
        # Dismiss failed
250 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "dismiss", app_id,
251 2070c5f8 Giorgos Korfiatis
                                     headers=h_owner)
252 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 409)
253 2556cf45 Giorgos Korfiatis
254 2556cf45 Giorgos Korfiatis
        # Deny
255 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "deny", app_id,
256 2070c5f8 Giorgos Korfiatis
                                     headers=h_admin)
257 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
258 2556cf45 Giorgos Korfiatis
259 2070c5f8 Giorgos Korfiatis
        # Get project
260 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_project",
261 2070c5f8 Giorgos Korfiatis
                               kwargs={"project_id": project_id}),
262 2556cf45 Giorgos Korfiatis
                       **h_owner)
263 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
264 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["id"], app_id)
265 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["state"], "denied")
266 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["state"], "uninitialized")
267 2556cf45 Giorgos Korfiatis
268 2556cf45 Giorgos Korfiatis
        # Dismiss
269 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "dismiss", app_id,
270 2070c5f8 Giorgos Korfiatis
                                     headers=h_owner)
271 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
272 2556cf45 Giorgos Korfiatis
273 2070c5f8 Giorgos Korfiatis
        # Get project
274 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_project",
275 2070c5f8 Giorgos Korfiatis
                               kwargs={"project_id": project_id}),
276 2070c5f8 Giorgos Korfiatis
                       **h_owner)
277 2070c5f8 Giorgos Korfiatis
        body = json.loads(r.content)
278 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["id"], app_id)
279 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["state"], "dismissed")
280 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["state"], "deleted")
281 2070c5f8 Giorgos Korfiatis
282 2070c5f8 Giorgos Korfiatis
        # Create the project again
283 2070c5f8 Giorgos Korfiatis
        status, body = self.create(app2, h_owner)
284 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 201)
285 2070c5f8 Giorgos Korfiatis
        project_id = body["id"]
286 2070c5f8 Giorgos Korfiatis
        app_id = body["application"]
287 2556cf45 Giorgos Korfiatis
288 2556cf45 Giorgos Korfiatis
        # Approve
289 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "approve", app_id,
290 2070c5f8 Giorgos Korfiatis
                                     headers=h_admin)
291 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
292 2556cf45 Giorgos Korfiatis
293 2070c5f8 Giorgos Korfiatis
        # Check memberships
294 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_memberships"), **h_plain)
295 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
296 2070c5f8 Giorgos Korfiatis
        self.assertEqual(len(body), 1)
297 2556cf45 Giorgos Korfiatis
298 2556cf45 Giorgos Korfiatis
        # Enroll
299 2556cf45 Giorgos Korfiatis
        status, body = self.enroll(project_id, self.user3, h_owner)
300 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
301 2556cf45 Giorgos Korfiatis
        m_plain_id = body["id"]
302 2556cf45 Giorgos Korfiatis
303 2070c5f8 Giorgos Korfiatis
        # Get project
304 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_project",
305 2070c5f8 Giorgos Korfiatis
                               kwargs={"project_id": project_id}),
306 2070c5f8 Giorgos Korfiatis
                       **h_owner)
307 2070c5f8 Giorgos Korfiatis
        body = json.loads(r.content)
308 2556cf45 Giorgos Korfiatis
        # Join
309 2556cf45 Giorgos Korfiatis
        status, body = self.join(project_id, h_owner)
310 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
311 2556cf45 Giorgos Korfiatis
        memb_id = body["id"]
312 2556cf45 Giorgos Korfiatis
313 2556cf45 Giorgos Korfiatis
        # Check memberships
314 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_memberships"), **h_plain)
315 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
316 2070c5f8 Giorgos Korfiatis
        self.assertEqual(len(body), 2)
317 2070c5f8 Giorgos Korfiatis
        m = find(lambda m: m["project"] == project_id, body)
318 2070c5f8 Giorgos Korfiatis
        self.assertNotEqual(m, NotFound)
319 2556cf45 Giorgos Korfiatis
        self.assertEqual(m["user"], self.user3.uuid)
320 2556cf45 Giorgos Korfiatis
        self.assertEqual(m["state"], "accepted")
321 2556cf45 Giorgos Korfiatis
322 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_memberships"), **h_owner)
323 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
324 2070c5f8 Giorgos Korfiatis
        self.assertEqual(len(body), 3)
325 2556cf45 Giorgos Korfiatis
326 2556cf45 Giorgos Korfiatis
        # Check membership
327 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_membership", kwargs={"memb_id": memb_id}),
328 2556cf45 Giorgos Korfiatis
                       **h_admin)
329 2556cf45 Giorgos Korfiatis
        m = json.loads(r.content)
330 2556cf45 Giorgos Korfiatis
        self.assertEqual(m["user"], self.user1.uuid)
331 2556cf45 Giorgos Korfiatis
        self.assertEqual(m["state"], "requested")
332 2556cf45 Giorgos Korfiatis
        self.assertEqual(sorted(m["allowed_actions"]),
333 2556cf45 Giorgos Korfiatis
                         ["accept", "cancel", "reject"])
334 2556cf45 Giorgos Korfiatis
335 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_membership", kwargs={"memb_id": memb_id}),
336 2556cf45 Giorgos Korfiatis
                       **h_plain)
337 2556cf45 Giorgos Korfiatis
        self.assertEqual(r.status_code, 403)
338 2556cf45 Giorgos Korfiatis
339 2556cf45 Giorgos Korfiatis
        status = self.memb_action(memb_id, "leave", h_admin)
340 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 409)
341 2556cf45 Giorgos Korfiatis
342 2556cf45 Giorgos Korfiatis
        status = self.memb_action(memb_id, "cancel", h_owner)
343 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
344 2556cf45 Giorgos Korfiatis
345 2556cf45 Giorgos Korfiatis
        status, body = self.join(project_id, h_owner)
346 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
347 2556cf45 Giorgos Korfiatis
        self.assertEqual(memb_id, body["id"])
348 2556cf45 Giorgos Korfiatis
349 2556cf45 Giorgos Korfiatis
        status = self.memb_action(memb_id, "reject", h_owner)
350 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
351 2556cf45 Giorgos Korfiatis
352 2556cf45 Giorgos Korfiatis
        status, body = self.join(project_id, h_owner)
353 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
354 2556cf45 Giorgos Korfiatis
        self.assertEqual(memb_id, body["id"])
355 2556cf45 Giorgos Korfiatis
356 2556cf45 Giorgos Korfiatis
        status = self.memb_action(memb_id, "accept", h_owner)
357 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
358 2556cf45 Giorgos Korfiatis
359 2556cf45 Giorgos Korfiatis
        # Enroll fails, already in
360 2556cf45 Giorgos Korfiatis
        status, body = self.enroll(project_id, self.user1, h_owner)
361 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 409)
362 2556cf45 Giorgos Korfiatis
363 2556cf45 Giorgos Korfiatis
        # Remove member
364 2556cf45 Giorgos Korfiatis
        status = self.memb_action(memb_id, "remove", h_owner)
365 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
366 2556cf45 Giorgos Korfiatis
367 2556cf45 Giorgos Korfiatis
        # Enroll a removed member
368 2556cf45 Giorgos Korfiatis
        status, body = self.enroll(project_id, self.user1, h_owner)
369 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
370 2556cf45 Giorgos Korfiatis
371 2556cf45 Giorgos Korfiatis
        # Remove member
372 2556cf45 Giorgos Korfiatis
        status = self.memb_action(memb_id, "remove", h_owner)
373 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
374 2556cf45 Giorgos Korfiatis
375 2556cf45 Giorgos Korfiatis
        # Re-join
376 2556cf45 Giorgos Korfiatis
        status, body = self.join(project_id, h_owner)
377 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
378 2556cf45 Giorgos Korfiatis
        self.assertEqual(memb_id, body["id"])
379 2556cf45 Giorgos Korfiatis
380 2556cf45 Giorgos Korfiatis
        # Enroll a requested member
381 2556cf45 Giorgos Korfiatis
        status, body = self.enroll(project_id, self.user1, h_owner)
382 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
383 2556cf45 Giorgos Korfiatis
384 2556cf45 Giorgos Korfiatis
        # Enroll fails, already in
385 2556cf45 Giorgos Korfiatis
        status, body = self.enroll(project_id, self.user1, h_owner)
386 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 409)
387 2556cf45 Giorgos Korfiatis
388 d915cf3c Giorgos Korfiatis
        # Enroll fails, project does not exist
389 d915cf3c Giorgos Korfiatis
        status, body = self.enroll(-1, self.user1, h_owner)
390 d915cf3c Giorgos Korfiatis
        self.assertEqual(status, 409)
391 d915cf3c Giorgos Korfiatis
392 2556cf45 Giorgos Korfiatis
        # Get projects
393 2556cf45 Giorgos Korfiatis
        ## Simple user mode
394 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_projects"), **h_plain)
395 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
396 2070c5f8 Giorgos Korfiatis
        self.assertEqual(len(body), 2)
397 2556cf45 Giorgos Korfiatis
        p = body[0]
398 2556cf45 Giorgos Korfiatis
        with assertRaises(KeyError):
399 2556cf45 Giorgos Korfiatis
            p["pending_application"]
400 2556cf45 Giorgos Korfiatis
401 2556cf45 Giorgos Korfiatis
        ## Owner mode
402 2070c5f8 Giorgos Korfiatis
        filters = {"state": "active"}
403 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_projects"), filters, **h_owner)
404 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
405 2556cf45 Giorgos Korfiatis
        self.assertEqual(len(body), 2)
406 2556cf45 Giorgos Korfiatis
407 2070c5f8 Giorgos Korfiatis
        filters = {"state": "deleted"}
408 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_projects"), filters, **h_owner)
409 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
410 2070c5f8 Giorgos Korfiatis
        self.assertEqual(len(body), 2)
411 2556cf45 Giorgos Korfiatis
412 2070c5f8 Giorgos Korfiatis
        filters = {"state": "uninitialized"}
413 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_projects"), filters, **h_owner)
414 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
415 2556cf45 Giorgos Korfiatis
        self.assertEqual(len(body), 2)
416 2556cf45 Giorgos Korfiatis
417 2070c5f8 Giorgos Korfiatis
        filters = {"name": "test.pr"}
418 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_projects"), filters, **h_owner)
419 2070c5f8 Giorgos Korfiatis
        body = json.loads(r.content)
420 2070c5f8 Giorgos Korfiatis
        self.assertEqual(len(body), 4)
421 2070c5f8 Giorgos Korfiatis
422 5d3a191e Giorgos Korfiatis
        filters = {"mode": "member"}
423 5d3a191e Giorgos Korfiatis
        r = client.get(reverse("api_projects"), filters, **h_owner)
424 5d3a191e Giorgos Korfiatis
        body = json.loads(r.content)
425 5d3a191e Giorgos Korfiatis
        self.assertEqual(len(body), 2)
426 5d3a191e Giorgos Korfiatis
427 2556cf45 Giorgos Korfiatis
        # Leave failed
428 2556cf45 Giorgos Korfiatis
        status = self.memb_action(m_plain_id, "leave", h_owner)
429 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 403)
430 2556cf45 Giorgos Korfiatis
431 2556cf45 Giorgos Korfiatis
        # Leave
432 2556cf45 Giorgos Korfiatis
        status = self.memb_action(m_plain_id, "leave", h_plain)
433 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
434 2556cf45 Giorgos Korfiatis
435 2556cf45 Giorgos Korfiatis
        # Suspend failed
436 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "suspend", headers=h_owner)
437 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 403)
438 2556cf45 Giorgos Korfiatis
439 2556cf45 Giorgos Korfiatis
        # Unsuspend failed
440 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "unsuspend", headers=h_admin)
441 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 409)
442 2556cf45 Giorgos Korfiatis
443 2556cf45 Giorgos Korfiatis
        # Suspend
444 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "suspend", headers=h_admin)
445 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
446 2556cf45 Giorgos Korfiatis
447 2556cf45 Giorgos Korfiatis
        # Cannot view project
448 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_project",
449 2556cf45 Giorgos Korfiatis
                               kwargs={"project_id": project_id}), **h_plain)
450 2556cf45 Giorgos Korfiatis
        self.assertEqual(r.status_code, 403)
451 2556cf45 Giorgos Korfiatis
452 2556cf45 Giorgos Korfiatis
        # Unsuspend
453 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "unsuspend", headers=h_admin)
454 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
455 2556cf45 Giorgos Korfiatis
456 2556cf45 Giorgos Korfiatis
        # Cannot approve, project with same name exists
457 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project2_id, "approve", project2_app_id,
458 2070c5f8 Giorgos Korfiatis
                                     headers=h_admin)
459 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 409)
460 2556cf45 Giorgos Korfiatis
461 2556cf45 Giorgos Korfiatis
        # Terminate
462 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "terminate", headers=h_admin)
463 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
464 2556cf45 Giorgos Korfiatis
465 2556cf45 Giorgos Korfiatis
        # Join failed
466 2556cf45 Giorgos Korfiatis
        status, _ = self.join(project_id, h_admin)
467 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 409)
468 2556cf45 Giorgos Korfiatis
469 2556cf45 Giorgos Korfiatis
        # Can approve now
470 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project2_id, "approve", project2_app_id,
471 2070c5f8 Giorgos Korfiatis
                                     headers=h_admin)
472 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
473 2556cf45 Giorgos Korfiatis
474 2556cf45 Giorgos Korfiatis
        # Join new project
475 2556cf45 Giorgos Korfiatis
        status, body = self.join(project2_id, h_plain)
476 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
477 2556cf45 Giorgos Korfiatis
        m_project2 = body["id"]
478 2556cf45 Giorgos Korfiatis
479 2556cf45 Giorgos Korfiatis
        # Get memberships of project
480 2070c5f8 Giorgos Korfiatis
        filters = {"project": project2_id}
481 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_memberships"), filters, **h_owner)
482 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
483 2556cf45 Giorgos Korfiatis
        self.assertEqual(len(body), 1)
484 2556cf45 Giorgos Korfiatis
        self.assertEqual(body[0]["id"], m_project2)
485 2556cf45 Giorgos Korfiatis
486 2556cf45 Giorgos Korfiatis
        # Remove member
487 2556cf45 Giorgos Korfiatis
        status = self.memb_action(m_project2, "remove", h_owner)
488 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 200)
489 2556cf45 Giorgos Korfiatis
490 2556cf45 Giorgos Korfiatis
        # Reinstate failed
491 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "reinstate", headers=h_admin)
492 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 409)
493 2556cf45 Giorgos Korfiatis
494 2556cf45 Giorgos Korfiatis
        # Rename
495 2556cf45 Giorgos Korfiatis
        app2_renamed = copy.deepcopy(app2)
496 2556cf45 Giorgos Korfiatis
        app2_renamed["name"] = "new.name"
497 2556cf45 Giorgos Korfiatis
        status, body = self.modify(app2_renamed, project_id, h_owner)
498 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 201)
499 2556cf45 Giorgos Korfiatis
        app2_renamed_id = body["application"]
500 2556cf45 Giorgos Korfiatis
501 2556cf45 Giorgos Korfiatis
        # Get project
502 2556cf45 Giorgos Korfiatis
        r = client.get(reverse("api_project",
503 2556cf45 Giorgos Korfiatis
                               kwargs={"project_id": project_id}), **h_owner)
504 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
505 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["id"], app2_renamed_id)
506 2556cf45 Giorgos Korfiatis
        self.assertEqual(body["state"], "terminated")
507 2556cf45 Giorgos Korfiatis
        assertIn("deactivation_date", body)
508 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["state"], "pending")
509 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["name"], "new.name")
510 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "approve", app2_renamed_id,
511 2070c5f8 Giorgos Korfiatis
                                     headers=h_admin)
512 2070c5f8 Giorgos Korfiatis
        self.assertEqual(r.status_code, 200)
513 2556cf45 Giorgos Korfiatis
514 2070c5f8 Giorgos Korfiatis
        # Change homepage
515 2070c5f8 Giorgos Korfiatis
        status, body = self.modify({"homepage": "new.page"},
516 2070c5f8 Giorgos Korfiatis
                                   project_id, h_owner)
517 2070c5f8 Giorgos Korfiatis
        self.assertEqual(status, 201)
518 2556cf45 Giorgos Korfiatis
519 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_project",
520 2070c5f8 Giorgos Korfiatis
                               kwargs={"project_id": project_id}), **h_owner)
521 2556cf45 Giorgos Korfiatis
        body = json.loads(r.content)
522 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["homepage"], "")
523 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["last_application"]["homepage"], "new.page")
524 2070c5f8 Giorgos Korfiatis
        homepage_app = body["last_application"]["id"]
525 2070c5f8 Giorgos Korfiatis
        status = self.project_action(project_id, "approve", homepage_app,
526 2070c5f8 Giorgos Korfiatis
                                     headers=h_admin)
527 2556cf45 Giorgos Korfiatis
        self.assertEqual(r.status_code, 200)
528 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_project",
529 2070c5f8 Giorgos Korfiatis
                               kwargs={"project_id": project_id}), **h_owner)
530 2070c5f8 Giorgos Korfiatis
        body = json.loads(r.content)
531 2070c5f8 Giorgos Korfiatis
        self.assertEqual(body["homepage"], "new.page")
532 2556cf45 Giorgos Korfiatis
533 2556cf45 Giorgos Korfiatis
        # Bad requests
534 2556cf45 Giorgos Korfiatis
        r = client.head(reverse("api_projects"), **h_admin)
535 2aba7764 Sofia Papagiannaki
        self.assertEqual(r.status_code, 405)
536 2aba7764 Sofia Papagiannaki
        self.assertTrue('Allow' in r)
537 2556cf45 Giorgos Korfiatis
538 2556cf45 Giorgos Korfiatis
        r = client.head(reverse("api_project",
539 2556cf45 Giorgos Korfiatis
                                kwargs={"project_id": 1}), **h_admin)
540 2aba7764 Sofia Papagiannaki
        self.assertEqual(r.status_code, 405)
541 2aba7764 Sofia Papagiannaki
        self.assertTrue('Allow' in r)
542 2556cf45 Giorgos Korfiatis
543 2556cf45 Giorgos Korfiatis
        r = client.head(reverse("api_memberships"), **h_admin)
544 2aba7764 Sofia Papagiannaki
        self.assertEqual(r.status_code, 405)
545 2aba7764 Sofia Papagiannaki
        self.assertTrue('Allow' in r)
546 2556cf45 Giorgos Korfiatis
547 2070c5f8 Giorgos Korfiatis
        status = self.project_action(1, "nonex", headers=h_owner)
548 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
549 2556cf45 Giorgos Korfiatis
550 2556cf45 Giorgos Korfiatis
        action = json.dumps({"suspend": "", "unsuspend": ""})
551 2556cf45 Giorgos Korfiatis
        r = client.post(reverse("api_project_action",
552 2556cf45 Giorgos Korfiatis
                                kwargs={"project_id": 1}),
553 2556cf45 Giorgos Korfiatis
                        action, content_type="application/json", **h_owner)
554 2556cf45 Giorgos Korfiatis
        self.assertEqual(r.status_code, 400)
555 2556cf45 Giorgos Korfiatis
556 2556cf45 Giorgos Korfiatis
        ap = {"owner": "nonex",
557 2556cf45 Giorgos Korfiatis
              "join_policy": "nonex",
558 2556cf45 Giorgos Korfiatis
              "leave_policy": "nonex",
559 2556cf45 Giorgos Korfiatis
              "start_date": "nonex",
560 2556cf45 Giorgos Korfiatis
              "homepage": {},
561 2556cf45 Giorgos Korfiatis
              "max_members": -3,
562 2556cf45 Giorgos Korfiatis
              "resources": [],
563 2556cf45 Giorgos Korfiatis
              }
564 2556cf45 Giorgos Korfiatis
565 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
566 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
567 2556cf45 Giorgos Korfiatis
        self.assertEqual(body["badRequest"]["message"], "User does not exist.")
568 2556cf45 Giorgos Korfiatis
569 2556cf45 Giorgos Korfiatis
        ap["owner"] = self.user1.uuid
570 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
571 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
572 2556cf45 Giorgos Korfiatis
573 2556cf45 Giorgos Korfiatis
        ap["name"] = "some.name"
574 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
575 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
576 2556cf45 Giorgos Korfiatis
577 2556cf45 Giorgos Korfiatis
        ap["join_policy"] = "auto"
578 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
579 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
580 2556cf45 Giorgos Korfiatis
581 2556cf45 Giorgos Korfiatis
        ap["leave_policy"] = "closed"
582 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
583 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
584 2556cf45 Giorgos Korfiatis
585 2556cf45 Giorgos Korfiatis
        ap["start_date"] = "2013-01-01T0:0Z"
586 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
587 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
588 2556cf45 Giorgos Korfiatis
589 2556cf45 Giorgos Korfiatis
        ap["end_date"] = "2014-01-01T0:0Z"
590 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
591 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
592 2556cf45 Giorgos Korfiatis
593 2556cf45 Giorgos Korfiatis
        ap["max_members"] = 0
594 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
595 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
596 2556cf45 Giorgos Korfiatis
597 2556cf45 Giorgos Korfiatis
        ap["homepage"] = "a.stri.ng"
598 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
599 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
600 2556cf45 Giorgos Korfiatis
601 2556cf45 Giorgos Korfiatis
        ap["resources"] = {42: 42}
602 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
603 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 400)
604 2556cf45 Giorgos Korfiatis
605 2070c5f8 Giorgos Korfiatis
        ap["resources"] = {"service1.resource11": {
606 2070c5f8 Giorgos Korfiatis
                "member_capacity": 512}}
607 2070c5f8 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
608 2070c5f8 Giorgos Korfiatis
        self.assertEqual(status, 400)
609 2070c5f8 Giorgos Korfiatis
610 2070c5f8 Giorgos Korfiatis
        ap["resources"] = {"service1.resource11": {"member_capacity": 512,
611 2070c5f8 Giorgos Korfiatis
                                                   "project_capacity": 1024}}
612 2556cf45 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
613 2556cf45 Giorgos Korfiatis
        self.assertEqual(status, 201)
614 2556cf45 Giorgos Korfiatis
615 a23ac2f7 Giorgos Korfiatis
        ap["name"] = "non_domain_name"
616 a23ac2f7 Giorgos Korfiatis
        status, body = self.create(ap, h_owner)
617 a23ac2f7 Giorgos Korfiatis
        self.assertEqual(status, 400)
618 a23ac2f7 Giorgos Korfiatis
619 e98239db Giorgos Korfiatis
        ap["name"] = "domain.name"
620 2556cf45 Giorgos Korfiatis
621 2070c5f8 Giorgos Korfiatis
        filters = {"state": "nonex"}
622 2070c5f8 Giorgos Korfiatis
        r = client.get(reverse("api_projects"), filters, **h_owner)
623 2556cf45 Giorgos Korfiatis
        self.assertEqual(r.status_code, 400)
624 1ac3349d Kostas Papadimitriou
625 5d3a191e Giorgos Korfiatis
        # directly modify a base project
626 5d3a191e Giorgos Korfiatis
        with assertRaises(functions.ProjectBadRequest):
627 5d3a191e Giorgos Korfiatis
            functions.modify_project(self.user1.uuid,
628 5d3a191e Giorgos Korfiatis
                                     {"description": "new description",
629 5d3a191e Giorgos Korfiatis
                                      "member_join_policy":
630 5d3a191e Giorgos Korfiatis
                                          functions.MODERATED_POLICY})
631 5d3a191e Giorgos Korfiatis
        functions.modify_project(self.user1.uuid,
632 5d3a191e Giorgos Korfiatis
                                 {"member_join_policy":
633 5d3a191e Giorgos Korfiatis
                                      functions.MODERATED_POLICY})
634 5d3a191e Giorgos Korfiatis
        r = client.get(reverse("api_project",
635 5d3a191e Giorgos Korfiatis
                               kwargs={"project_id": self.user1.uuid}),
636 5d3a191e Giorgos Korfiatis
                       **h_owner)
637 5d3a191e Giorgos Korfiatis
        body = json.loads(r.content)
638 5d3a191e Giorgos Korfiatis
        self.assertEqual(body["join_policy"], "moderated")
639 5d3a191e Giorgos Korfiatis
640 1ac3349d Kostas Papadimitriou
641 1ac3349d Kostas Papadimitriou
class TestProjects(TestCase):
642 1ac3349d Kostas Papadimitriou
    """
643 1ac3349d Kostas Papadimitriou
    Test projects.
644 1ac3349d Kostas Papadimitriou
    """
645 1ac3349d Kostas Papadimitriou
    def setUp(self):
646 1ac3349d Kostas Papadimitriou
        # astakos resources
647 1ac3349d Kostas Papadimitriou
        self.resource = Resource.objects.create(name="astakos.pending_app",
648 1ac3349d Kostas Papadimitriou
                                                uplimit=0,
649 2070c5f8 Giorgos Korfiatis
                                                project_default=0,
650 2dc27ac1 Giorgos Korfiatis
                                                ui_visible=False,
651 2dc27ac1 Giorgos Korfiatis
                                                api_visible=False,
652 bd1f667b Giorgos Korfiatis
                                                service_type="astakos")
653 1ac3349d Kostas Papadimitriou
654 1ac3349d Kostas Papadimitriou
        # custom service resources
655 1ac3349d Kostas Papadimitriou
        self.resource = Resource.objects.create(name="service1.resource",
656 1ac3349d Kostas Papadimitriou
                                                uplimit=100,
657 2070c5f8 Giorgos Korfiatis
                                                project_default=0,
658 bd1f667b Giorgos Korfiatis
                                                service_type="service1")
659 1ac3349d Kostas Papadimitriou
        self.admin = get_local_user("projects-admin@synnefo.org")
660 1ac3349d Kostas Papadimitriou
        self.admin.uuid = 'uuid1'
661 1ac3349d Kostas Papadimitriou
        self.admin.save()
662 1ac3349d Kostas Papadimitriou
663 1ac3349d Kostas Papadimitriou
        self.user = get_local_user("user@synnefo.org")
664 1ac3349d Kostas Papadimitriou
        self.member = get_local_user("member@synnefo.org")
665 1ac3349d Kostas Papadimitriou
        self.member2 = get_local_user("member2@synnefo.org")
666 1ac3349d Kostas Papadimitriou
667 1ac3349d Kostas Papadimitriou
        self.admin_client = get_user_client("projects-admin@synnefo.org")
668 1ac3349d Kostas Papadimitriou
        self.user_client = get_user_client("user@synnefo.org")
669 1ac3349d Kostas Papadimitriou
        self.member_client = get_user_client("member@synnefo.org")
670 1ac3349d Kostas Papadimitriou
        self.member2_client = get_user_client("member2@synnefo.org")
671 1ac3349d Kostas Papadimitriou
672 baa9073a Kostas Papadimitriou
    def tearDown(self):
673 baa9073a Kostas Papadimitriou
        Service.objects.all().delete()
674 baa9073a Kostas Papadimitriou
        ProjectApplication.objects.all().delete()
675 fce2ebcb Kostas Papadimitriou
        Project.objects.all().delete()
676 fce2ebcb Kostas Papadimitriou
        AstakosUser.objects.all().delete()
677 baa9073a Kostas Papadimitriou
678 1ac3349d Kostas Papadimitriou
    @im_settings(PROJECT_ADMINS=['uuid1'])
679 1ac3349d Kostas Papadimitriou
    def test_application_limit(self):
680 1ac3349d Kostas Papadimitriou
        # user cannot create a project
681 1ac3349d Kostas Papadimitriou
        r = self.user_client.get(reverse('project_add'), follow=True)
682 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_list'))
683 1ac3349d Kostas Papadimitriou
        self.assertContains(r, "You are not allowed to create a new project")
684 1ac3349d Kostas Papadimitriou
685 1ac3349d Kostas Papadimitriou
        # but admin can
686 1ac3349d Kostas Papadimitriou
        r = self.admin_client.get(reverse('project_add'), follow=True)
687 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_add'))
688 1ac3349d Kostas Papadimitriou
689 1ac3349d Kostas Papadimitriou
    @im_settings(PROJECT_ADMINS=['uuid1'])
690 2dc27ac1 Giorgos Korfiatis
    def test_ui_visible(self):
691 1ac3349d Kostas Papadimitriou
        dfrom = datetime.now()
692 1ac3349d Kostas Papadimitriou
        dto = datetime.now() + timedelta(days=30)
693 1ac3349d Kostas Papadimitriou
694 2dc27ac1 Giorgos Korfiatis
        # astakos.pending_app ui_visible flag is False
695 1ac3349d Kostas Papadimitriou
        # we shouldn't be able to create a project application using this
696 1ac3349d Kostas Papadimitriou
        # resource.
697 1ac3349d Kostas Papadimitriou
        application_data = {
698 1ac3349d Kostas Papadimitriou
            'name': 'project.synnefo.org',
699 1ac3349d Kostas Papadimitriou
            'homepage': 'https://www.synnefo.org',
700 1ac3349d Kostas Papadimitriou
            'start_date': dfrom.strftime("%Y-%m-%d"),
701 1ac3349d Kostas Papadimitriou
            'end_date': dto.strftime("%Y-%m-%d"),
702 1ac3349d Kostas Papadimitriou
            'member_join_policy': 2,
703 1ac3349d Kostas Papadimitriou
            'member_leave_policy': 1,
704 e98239db Giorgos Korfiatis
            'limit_on_members_number': 5,
705 0486dc60 Giorgos Korfiatis
            'service1.resource_m_uplimit': 100,
706 1ac3349d Kostas Papadimitriou
            'is_selected_service1.resource': "1",
707 0486dc60 Giorgos Korfiatis
            'astakos.pending_app_m_uplimit': 100,
708 1ac3349d Kostas Papadimitriou
            'is_selected_accounts': "1",
709 1ac3349d Kostas Papadimitriou
            'user': self.user.pk
710 1ac3349d Kostas Papadimitriou
        }
711 1ac3349d Kostas Papadimitriou
        form = forms.ProjectApplicationForm(data=application_data)
712 1ac3349d Kostas Papadimitriou
        # form is invalid
713 1ac3349d Kostas Papadimitriou
        self.assertEqual(form.is_valid(), False)
714 1ac3349d Kostas Papadimitriou
715 0486dc60 Giorgos Korfiatis
        del application_data['astakos.pending_app_m_uplimit']
716 1ac3349d Kostas Papadimitriou
        del application_data['is_selected_accounts']
717 1ac3349d Kostas Papadimitriou
        form = forms.ProjectApplicationForm(data=application_data)
718 1ac3349d Kostas Papadimitriou
        self.assertEqual(form.is_valid(), True)
719 1ac3349d Kostas Papadimitriou
720 1ac3349d Kostas Papadimitriou
    @im_settings(PROJECT_ADMINS=['uuid1'])
721 0486dc60 Giorgos Korfiatis
    def no_test_applications(self):
722 1ac3349d Kostas Papadimitriou
        # let user have 2 pending applications
723 2070c5f8 Giorgos Korfiatis
724 2070c5f8 Giorgos Korfiatis
        # TODO figure this out
725 2070c5f8 Giorgos Korfiatis
        request = {"resources": {"astakos.pending_app":
726 0486dc60 Giorgos Korfiatis
                                     {"member_capacity": 2,
727 0486dc60 Giorgos Korfiatis
                                      "project_capacity": 2}}}
728 2070c5f8 Giorgos Korfiatis
        functions.modify_project(self.user.uuid, request)
729 1ac3349d Kostas Papadimitriou
730 1ac3349d Kostas Papadimitriou
        r = self.user_client.get(reverse('project_add'), follow=True)
731 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_add'))
732 1ac3349d Kostas Papadimitriou
733 1ac3349d Kostas Papadimitriou
        # user fills the project application form
734 1ac3349d Kostas Papadimitriou
        post_url = reverse('project_add') + '?verify=1'
735 1ac3349d Kostas Papadimitriou
        dfrom = datetime.now()
736 1ac3349d Kostas Papadimitriou
        dto = datetime.now() + timedelta(days=30)
737 1ac3349d Kostas Papadimitriou
        application_data = {
738 1ac3349d Kostas Papadimitriou
            'name': 'project.synnefo.org',
739 1ac3349d Kostas Papadimitriou
            'homepage': 'https://www.synnefo.org',
740 1ac3349d Kostas Papadimitriou
            'start_date': dfrom.strftime("%Y-%m-%d"),
741 1ac3349d Kostas Papadimitriou
            'end_date': dto.strftime("%Y-%m-%d"),
742 1ac3349d Kostas Papadimitriou
            'member_join_policy': 2,
743 1ac3349d Kostas Papadimitriou
            'member_leave_policy': 1,
744 0486dc60 Giorgos Korfiatis
            'service1.resource_m_uplimit': 100,
745 1ac3349d Kostas Papadimitriou
            'is_selected_service1.resource': "1",
746 1ac3349d Kostas Papadimitriou
            'user': self.user.pk
747 1ac3349d Kostas Papadimitriou
        }
748 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(post_url, data=application_data, follow=True)
749 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
750 e98239db Giorgos Korfiatis
        self.assertEqual(r.context['form'].is_valid(), False)
751 e98239db Giorgos Korfiatis
752 e98239db Giorgos Korfiatis
        application_data['limit_on_members_number'] = 5
753 e98239db Giorgos Korfiatis
        r = self.user_client.post(post_url, data=application_data, follow=True)
754 e98239db Giorgos Korfiatis
        self.assertEqual(r.status_code, 200)
755 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.context['form'].is_valid(), True)
756 1ac3349d Kostas Papadimitriou
757 1ac3349d Kostas Papadimitriou
        # confirm request
758 1ac3349d Kostas Papadimitriou
        post_url = reverse('project_add') + '?verify=0&edit=0'
759 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(post_url, data=application_data, follow=True)
760 1ac3349d Kostas Papadimitriou
        self.assertContains(r, "The project application has been received")
761 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_list'))
762 1ac3349d Kostas Papadimitriou
        self.assertEqual(ProjectApplication.objects.count(), 1)
763 50f74340 Giorgos Korfiatis
        app1 = ProjectApplication.objects.filter().order_by('pk')[0]
764 50f74340 Giorgos Korfiatis
        app1_id = app1.pk
765 50f74340 Giorgos Korfiatis
        project1_id = app1.chain_id
766 1ac3349d Kostas Papadimitriou
767 1ac3349d Kostas Papadimitriou
        # create another one
768 1ac3349d Kostas Papadimitriou
        application_data['name'] = 'project2.synnefo.org'
769 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(post_url, data=application_data, follow=True)
770 50f74340 Giorgos Korfiatis
        app2 = ProjectApplication.objects.filter().order_by('pk')[1]
771 50f74340 Giorgos Korfiatis
        project2_id = app2.chain_id
772 1ac3349d Kostas Papadimitriou
773 1ac3349d Kostas Papadimitriou
        # no more applications (LIMIT is 2)
774 1ac3349d Kostas Papadimitriou
        r = self.user_client.get(reverse('project_add'), follow=True)
775 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_list'))
776 1ac3349d Kostas Papadimitriou
        self.assertContains(r, "You are not allowed to create a new project")
777 1ac3349d Kostas Papadimitriou
778 50f74340 Giorgos Korfiatis
        # one project per application
779 0486dc60 Giorgos Korfiatis
        self.assertEqual(Project.objects.filter(is_base=False).count(), 2)
780 50f74340 Giorgos Korfiatis
781 1ac3349d Kostas Papadimitriou
        # login
782 1ac3349d Kostas Papadimitriou
        self.admin_client.get(reverse("edit_profile"))
783 1ac3349d Kostas Papadimitriou
        # admin approves
784 1ac3349d Kostas Papadimitriou
        r = self.admin_client.post(reverse('project_app_approve',
785 1ac3349d Kostas Papadimitriou
                                           kwargs={'application_id': app1_id}),
786 1ac3349d Kostas Papadimitriou
                                   follow=True)
787 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
788 1ac3349d Kostas Papadimitriou
789 50f74340 Giorgos Korfiatis
        Q_ACTIVE = Project.o_state_q(Project.O_ACTIVE)
790 50f74340 Giorgos Korfiatis
        self.assertEqual(Project.objects.filter(Q_ACTIVE).count(), 1)
791 1ac3349d Kostas Papadimitriou
792 1ac3349d Kostas Papadimitriou
        # login
793 1ac3349d Kostas Papadimitriou
        self.member_client.get(reverse("edit_profile"))
794 50f74340 Giorgos Korfiatis
        # cannot join project2 (not approved yet)
795 50f74340 Giorgos Korfiatis
        join_url = reverse("project_join", kwargs={'chain_id': project2_id})
796 1ac3349d Kostas Papadimitriou
        r = self.member_client.post(join_url, follow=True)
797 1ac3349d Kostas Papadimitriou
798 50f74340 Giorgos Korfiatis
        # can join project1
799 1ac3349d Kostas Papadimitriou
        self.member_client.get(reverse("edit_profile"))
800 50f74340 Giorgos Korfiatis
        join_url = reverse("project_join", kwargs={'chain_id': project1_id})
801 1ac3349d Kostas Papadimitriou
        r = self.member_client.post(join_url, follow=True)
802 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
803 1ac3349d Kostas Papadimitriou
804 1ac3349d Kostas Papadimitriou
        memberships = ProjectMembership.objects.all()
805 1ac3349d Kostas Papadimitriou
        self.assertEqual(len(memberships), 1)
806 1ac3349d Kostas Papadimitriou
        memb_id = memberships[0].id
807 1ac3349d Kostas Papadimitriou
808 1ac3349d Kostas Papadimitriou
        reject_member_url = reverse('project_reject_member',
809 50f74340 Giorgos Korfiatis
                                    kwargs={'memb_id': memb_id})
810 1ac3349d Kostas Papadimitriou
        accept_member_url = reverse('project_accept_member',
811 50f74340 Giorgos Korfiatis
                                    kwargs={'memb_id': memb_id})
812 1ac3349d Kostas Papadimitriou
813 1ac3349d Kostas Papadimitriou
        # only project owner is allowed to reject
814 1ac3349d Kostas Papadimitriou
        r = self.member_client.post(reject_member_url, follow=True)
815 1ac3349d Kostas Papadimitriou
        self.assertContains(r, "You do not have the permissions")
816 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
817 1ac3349d Kostas Papadimitriou
818 1ac3349d Kostas Papadimitriou
        # user (owns project) rejects membership
819 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(reject_member_url, follow=True)
820 50f74340 Giorgos Korfiatis
        self.assertEqual(ProjectMembership.objects.any_accepted().count(), 0)
821 1ac3349d Kostas Papadimitriou
822 1ac3349d Kostas Papadimitriou
        # user rejoins
823 1ac3349d Kostas Papadimitriou
        self.member_client.get(reverse("edit_profile"))
824 0e553052 Giorgos Korfiatis
        join_url = reverse("project_join", kwargs={'chain_id': project1_id})
825 1ac3349d Kostas Papadimitriou
        r = self.member_client.post(join_url, follow=True)
826 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
827 50f74340 Giorgos Korfiatis
        self.assertEqual(ProjectMembership.objects.requested().count(), 1)
828 1ac3349d Kostas Papadimitriou
829 1ac3349d Kostas Papadimitriou
        # user (owns project) accepts membership
830 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(accept_member_url, follow=True)
831 50f74340 Giorgos Korfiatis
        self.assertEqual(ProjectMembership.objects.any_accepted().count(), 1)
832 1ac3349d Kostas Papadimitriou
        membership = ProjectMembership.objects.get()
833 1ac3349d Kostas Papadimitriou
        self.assertEqual(membership.state, ProjectMembership.ACCEPTED)
834 1ac3349d Kostas Papadimitriou
835 1ac3349d Kostas Papadimitriou
        user_quotas = quotas.get_users_quotas([self.member])
836 1ac3349d Kostas Papadimitriou
        resource = 'service1.resource'
837 1ac3349d Kostas Papadimitriou
        newlimit = user_quotas[self.member.uuid]['system'][resource]['limit']
838 1ac3349d Kostas Papadimitriou
        # 100 from initial uplimit + 100 from project
839 1ac3349d Kostas Papadimitriou
        self.assertEqual(newlimit, 200)
840 1ac3349d Kostas Papadimitriou
841 1ac3349d Kostas Papadimitriou
        remove_member_url = reverse('project_remove_member',
842 50f74340 Giorgos Korfiatis
                                    kwargs={'memb_id': membership.id})
843 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(remove_member_url, follow=True)
844 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
845 1ac3349d Kostas Papadimitriou
846 1ac3349d Kostas Papadimitriou
        user_quotas = quotas.get_users_quotas([self.member])
847 1ac3349d Kostas Papadimitriou
        resource = 'service1.resource'
848 1ac3349d Kostas Papadimitriou
        newlimit = user_quotas[self.member.uuid]['system'][resource]['limit']
849 1ac3349d Kostas Papadimitriou
        # 200 - 100 from project
850 1ac3349d Kostas Papadimitriou
        self.assertEqual(newlimit, 100)
851 b130ec7c Kostas Papadimitriou
852 b130ec7c Kostas Papadimitriou
        # support email gets rendered in emails content
853 b130ec7c Kostas Papadimitriou
        for mail in get_mailbox('user@synnefo.org'):
854 d4e4e501 Christos Stavrakakis
            self.assertTrue(settings.CONTACT_EMAIL in
855 b130ec7c Kostas Papadimitriou
                            mail.message().as_string())