Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / tests / projects.py @ 0486dc60

History | View | Annotate | Download (32.3 kB)

1
# Copyright 2011, 2012, 2013 GRNET S.A. All rights reserved.
2
#
3
# Redistribution and use in source and binary forms, with or
4
# without modification, are permitted provided that the following
5
# conditions are met:
6
#
7
#   1. Redistributions of source code must retain the above
8
#      copyright notice, this list of conditions and the following
9
#      disclaimer.
10
#
11
#   2. Redistributions in binary form must reproduce the above
12
#      copyright notice, this list of conditions and the following
13
#      disclaimer in the documentation and/or other materials
14
#      provided with the distribution.
15
#
16
# THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
17
# OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18
# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
20
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21
# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22
# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
23
# USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
24
# AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
26
# ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27
# POSSIBILITY OF SUCH DAMAGE.
28
#
29
# The views and conclusions contained in the software and
30
# documentation are those of the authors and should not be
31
# interpreted as representing official policies, either expressed
32
# or implied, of GRNET S.A.
33

    
34
from astakos.im.tests.common import *
35

    
36

    
37
NotFound = type('NotFound', (), {})
38

    
39

    
40
def find(f, seq):
41
    for item in seq:
42
        if f(item):
43
            return item
44
    return NotFound
45

    
46

    
47
class ProjectAPITest(TestCase):
48

    
49
    def setUp(self):
50
        self.client = Client()
51
        component1 = Component.objects.create(name="comp1")
52
        register.add_service(component1, "service1", "type1", [])
53
        # custom service resources
54
        resource11 = {"name": "service1.resource11",
55
                      "desc": "resource11 desc",
56
                      "service_type": "type1",
57
                      "service_origin": "service1",
58
                      "ui_visible": True}
59
        r, _ = register.add_resource(resource11)
60
        register.update_base_default(r, 100)
61
        resource12 = {"name": "service1.resource12",
62
                      "desc": "resource11 desc",
63
                      "service_type": "type1",
64
                      "service_origin": "service1",
65
                      "unit": "bytes"}
66
        r, _ = register.add_resource(resource12)
67
        register.update_base_default(r, 1024)
68

    
69
        # create user
70
        self.user1 = get_local_user("test@grnet.gr")
71
        self.user2 = get_local_user("test2@grnet.gr")
72
        self.user2.uuid = "uuid2"
73
        self.user2.save()
74
        self.user3 = get_local_user("test3@grnet.gr")
75

    
76
        astakos = Component.objects.create(name="astakos")
77
        register.add_service(astakos, "astakos_account", "account", [])
78
        # create another service
79
        pending_app = {"name": "astakos.pending_app",
80
                       "desc": "pend app desc",
81
                       "service_type": "account",
82
                       "service_origin": "astakos_account",
83
                       "ui_visible": False,
84
                       "api_visible": False}
85
        r, _ = register.add_resource(pending_app)
86
        register.update_base_default(r, 3)
87
        request = {"resources": {r.name: {"member_capacity": 3,
88
                                          "project_capacity": 3}}}
89
        functions.modify_projects_in_bulk(Q(is_base=True), request)
90

    
91
    def create(self, app, headers):
92
        dump = json.dumps(app)
93
        r = self.client.post(reverse("api_projects"), dump,
94
                             content_type="application/json", **headers)
95
        body = json.loads(r.content)
96
        return r.status_code, body
97

    
98
    def modify(self, app, project_id, headers):
99
        dump = json.dumps(app)
100
        kwargs = {"project_id": project_id}
101
        r = self.client.put(reverse("api_project", kwargs=kwargs), dump,
102
                             content_type="application/json", **headers)
103
        body = json.loads(r.content)
104
        return r.status_code, body
105

    
106
    def project_action(self, project_id, action, app_id=None, headers=None):
107
        action_data = {"reason": ""}
108
        if app_id is not None:
109
            action_data["app_id"] = app_id
110
        action = json.dumps({action: action_data})
111
        r = self.client.post(reverse("api_project_action",
112
                                     kwargs={"project_id": project_id}),
113
                             action, content_type="application/json",
114
                             **headers)
115
        return r.status_code
116

    
117
    def memb_action(self, memb_id, action, headers):
118
        action = json.dumps({action: "reason"})
119
        r = self.client.post(reverse("api_membership_action",
120
                                     kwargs={"memb_id": memb_id}), action,
121
                             content_type="application/json", **headers)
122
        return r.status_code
123

    
124
    def join(self, project_id, headers):
125
        action = {"join": {"project": project_id}}
126
        req = json.dumps(action)
127
        r = self.client.post(reverse("api_memberships"), req,
128
                             content_type="application/json", **headers)
129
        body = json.loads(r.content)
130
        return r.status_code, body
131

    
132
    def enroll(self, project_id, user, headers):
133
        action = {
134
            "enroll": {
135
                "project": project_id,
136
                "user": user.email,
137
            }
138
        }
139
        req = json.dumps(action)
140
        r = self.client.post(reverse("api_memberships"), req,
141
                             content_type="application/json", **headers)
142
        body = json.loads(r.content)
143
        return r.status_code, body
144

    
145
    @im_settings(PROJECT_ADMINS=["uuid2"])
146
    def test_projects(self):
147
        client = self.client
148
        h_owner = {"HTTP_X_AUTH_TOKEN": self.user1.auth_token}
149
        h_admin = {"HTTP_X_AUTH_TOKEN": self.user2.auth_token}
150
        h_plain = {"HTTP_X_AUTH_TOKEN": self.user3.auth_token}
151
        r = client.get(reverse("api_project", kwargs={"project_id": 1}))
152
        self.assertEqual(r.status_code, 401)
153

    
154
        r = client.get(reverse("api_project", kwargs={"project_id": 1}),
155
                       **h_owner)
156
        self.assertEqual(r.status_code, 404)
157
        r = client.get(reverse("api_membership", kwargs={"memb_id": 100}),
158
                       **h_owner)
159
        self.assertEqual(r.status_code, 404)
160

    
161
        status = self.memb_action(1, "accept", h_admin)
162
        self.assertEqual(status, 409)
163

    
164
        app1 = {"name": "test.pr",
165
                "end_date": "2013-5-5T20:20:20Z",
166
                "join_policy": "auto",
167
                "max_members": 5,
168
                "resources": {"service1.resource11": {
169
                    "project_capacity": 1024,
170
                    "member_capacity": 512}}
171
                }
172

    
173
        status, body = self.modify(app1, 100, h_owner)
174
        self.assertEqual(status, 404)
175

    
176
        # Create
177
        status, body = self.create(app1, h_owner)
178
        self.assertEqual(status, 201)
179
        project_id = body["id"]
180
        app_id = body["application"]
181

    
182
        # Get project
183
        r = client.get(reverse("api_project",
184
                               kwargs={"project_id": project_id}),
185
                       **h_owner)
186
        self.assertEqual(r.status_code, 200)
187
        body = json.loads(r.content)
188
        self.assertEqual(body["id"], project_id)
189
        self.assertEqual(body["last_application"]["id"], app_id)
190
        self.assertEqual(body["last_application"]["state"], "pending")
191
        self.assertEqual(body["state"], "uninitialized")
192
        self.assertEqual(body["owner"], self.user1.uuid)
193

    
194
        # Approve forbidden
195
        status = self.project_action(project_id, "approve", app_id=app_id,
196
                                     headers=h_owner)
197
        self.assertEqual(status, 403)
198

    
199
        # Create another with the same name
200
        status, body = self.create(app1, h_owner)
201
        self.assertEqual(status, 201)
202
        project2_id = body["id"]
203
        project2_app_id = body["application"]
204

    
205
        # Create yet another, with different name
206
        app_p3 = copy.deepcopy(app1)
207
        app_p3["name"] = "new.pr"
208
        status, body = self.create(app_p3, h_owner)
209
        self.assertEqual(status, 201)
210
        project3_id = body["id"]
211
        project3_app_id = body["application"]
212

    
213
        # No more pending allowed
214
        status, body = self.create(app_p3, h_owner)
215
        self.assertEqual(status, 409)
216

    
217
        # Cancel
218
        status = self.project_action(project3_id, "cancel",
219
                                     app_id=project3_app_id, headers=h_owner)
220
        self.assertEqual(status, 200)
221

    
222
        # Get project
223
        r = client.get(reverse("api_project",
224
                               kwargs={"project_id": project3_id}),
225
                       **h_owner)
226
        body = json.loads(r.content)
227
        self.assertEqual(body["state"], "deleted")
228

    
229
        # Modify of uninitialized failed
230
        app2 = {"name": "test.pr",
231
                "start_date": "2013-5-5T20:20:20Z",
232
                "end_date": "2013-7-5T20:20:20Z",
233
                "join_policy": "moderated",
234
                "leave_policy": "auto",
235
                "max_members": 3,
236
                "resources": {"service1.resource11": {
237
                    "project_capacity": 1024,
238
                    "member_capacity": 1024}}
239
                }
240
        status, body = self.modify(app2, project_id, h_owner)
241
        self.assertEqual(status, 409)
242

    
243
        # Create the project again
244
        status, body = self.create(app2, h_owner)
245
        self.assertEqual(status, 201)
246
        project_id = body["id"]
247
        app_id = body["application"]
248

    
249
        # Dismiss failed
250
        status = self.project_action(project_id, "dismiss", app_id,
251
                                     headers=h_owner)
252
        self.assertEqual(status, 409)
253

    
254
        # Deny
255
        status = self.project_action(project_id, "deny", app_id,
256
                                     headers=h_admin)
257
        self.assertEqual(status, 200)
258

    
259
        # Get project
260
        r = client.get(reverse("api_project",
261
                               kwargs={"project_id": project_id}),
262
                       **h_owner)
263
        body = json.loads(r.content)
264
        self.assertEqual(body["last_application"]["id"], app_id)
265
        self.assertEqual(body["last_application"]["state"], "denied")
266
        self.assertEqual(body["state"], "uninitialized")
267

    
268
        # Dismiss
269
        status = self.project_action(project_id, "dismiss", app_id,
270
                                     headers=h_owner)
271
        self.assertEqual(status, 200)
272

    
273
        # Get project
274
        r = client.get(reverse("api_project",
275
                               kwargs={"project_id": project_id}),
276
                       **h_owner)
277
        body = json.loads(r.content)
278
        self.assertEqual(body["last_application"]["id"], app_id)
279
        self.assertEqual(body["last_application"]["state"], "dismissed")
280
        self.assertEqual(body["state"], "deleted")
281

    
282
        # Create the project again
283
        status, body = self.create(app2, h_owner)
284
        self.assertEqual(status, 201)
285
        project_id = body["id"]
286
        app_id = body["application"]
287

    
288
        # Approve
289
        status = self.project_action(project_id, "approve", app_id,
290
                                     headers=h_admin)
291
        self.assertEqual(status, 200)
292

    
293
        # Check memberships
294
        r = client.get(reverse("api_memberships"), **h_plain)
295
        body = json.loads(r.content)
296
        self.assertEqual(len(body), 1)
297

    
298
        # Enroll
299
        status, body = self.enroll(project_id, self.user3, h_owner)
300
        self.assertEqual(status, 200)
301
        m_plain_id = body["id"]
302

    
303
        # Get project
304
        r = client.get(reverse("api_project",
305
                               kwargs={"project_id": project_id}),
306
                       **h_owner)
307
        body = json.loads(r.content)
308
        # Join
309
        status, body = self.join(project_id, h_owner)
310
        self.assertEqual(status, 200)
311
        memb_id = body["id"]
312

    
313
        # Check memberships
314
        r = client.get(reverse("api_memberships"), **h_plain)
315
        body = json.loads(r.content)
316
        self.assertEqual(len(body), 2)
317
        m = find(lambda m: m["project"] == project_id, body)
318
        self.assertNotEqual(m, NotFound)
319
        self.assertEqual(m["user"], self.user3.uuid)
320
        self.assertEqual(m["state"], "accepted")
321

    
322
        r = client.get(reverse("api_memberships"), **h_owner)
323
        body = json.loads(r.content)
324
        self.assertEqual(len(body), 3)
325

    
326
        # Check membership
327
        r = client.get(reverse("api_membership", kwargs={"memb_id": memb_id}),
328
                       **h_admin)
329
        m = json.loads(r.content)
330
        self.assertEqual(m["user"], self.user1.uuid)
331
        self.assertEqual(m["state"], "requested")
332
        self.assertEqual(sorted(m["allowed_actions"]),
333
                         ["accept", "cancel", "reject"])
334

    
335
        r = client.get(reverse("api_membership", kwargs={"memb_id": memb_id}),
336
                       **h_plain)
337
        self.assertEqual(r.status_code, 403)
338

    
339
        status = self.memb_action(memb_id, "leave", h_admin)
340
        self.assertEqual(status, 409)
341

    
342
        status = self.memb_action(memb_id, "cancel", h_owner)
343
        self.assertEqual(status, 200)
344

    
345
        status, body = self.join(project_id, h_owner)
346
        self.assertEqual(status, 200)
347
        self.assertEqual(memb_id, body["id"])
348

    
349
        status = self.memb_action(memb_id, "reject", h_owner)
350
        self.assertEqual(status, 200)
351

    
352
        status, body = self.join(project_id, h_owner)
353
        self.assertEqual(status, 200)
354
        self.assertEqual(memb_id, body["id"])
355

    
356
        status = self.memb_action(memb_id, "accept", h_owner)
357
        self.assertEqual(status, 200)
358

    
359
        # Enroll fails, already in
360
        status, body = self.enroll(project_id, self.user1, h_owner)
361
        self.assertEqual(status, 409)
362

    
363
        # Remove member
364
        status = self.memb_action(memb_id, "remove", h_owner)
365
        self.assertEqual(status, 200)
366

    
367
        # Enroll a removed member
368
        status, body = self.enroll(project_id, self.user1, h_owner)
369
        self.assertEqual(status, 200)
370

    
371
        # Remove member
372
        status = self.memb_action(memb_id, "remove", h_owner)
373
        self.assertEqual(status, 200)
374

    
375
        # Re-join
376
        status, body = self.join(project_id, h_owner)
377
        self.assertEqual(status, 200)
378
        self.assertEqual(memb_id, body["id"])
379

    
380
        # Enroll a requested member
381
        status, body = self.enroll(project_id, self.user1, h_owner)
382
        self.assertEqual(status, 200)
383

    
384
        # Enroll fails, already in
385
        status, body = self.enroll(project_id, self.user1, h_owner)
386
        self.assertEqual(status, 409)
387

    
388
        # Enroll fails, project does not exist
389
        status, body = self.enroll(-1, self.user1, h_owner)
390
        self.assertEqual(status, 409)
391

    
392
        # Get projects
393
        ## Simple user mode
394
        r = client.get(reverse("api_projects"), **h_plain)
395
        body = json.loads(r.content)
396
        self.assertEqual(len(body), 2)
397
        p = body[0]
398
        with assertRaises(KeyError):
399
            p["pending_application"]
400

    
401
        ## Owner mode
402
        filters = {"state": "active"}
403
        r = client.get(reverse("api_projects"), filters, **h_owner)
404
        body = json.loads(r.content)
405
        self.assertEqual(len(body), 2)
406

    
407
        filters = {"state": "deleted"}
408
        r = client.get(reverse("api_projects"), filters, **h_owner)
409
        body = json.loads(r.content)
410
        self.assertEqual(len(body), 2)
411

    
412
        filters = {"state": "uninitialized"}
413
        r = client.get(reverse("api_projects"), filters, **h_owner)
414
        body = json.loads(r.content)
415
        self.assertEqual(len(body), 2)
416

    
417
        filters = {"name": "test.pr"}
418
        r = client.get(reverse("api_projects"), filters, **h_owner)
419
        body = json.loads(r.content)
420
        self.assertEqual(len(body), 4)
421

    
422
        # Leave failed
423
        status = self.memb_action(m_plain_id, "leave", h_owner)
424
        self.assertEqual(status, 403)
425

    
426
        # Leave
427
        status = self.memb_action(m_plain_id, "leave", h_plain)
428
        self.assertEqual(status, 200)
429

    
430
        # Suspend failed
431
        status = self.project_action(project_id, "suspend", headers=h_owner)
432
        self.assertEqual(status, 403)
433

    
434
        # Unsuspend failed
435
        status = self.project_action(project_id, "unsuspend", headers=h_admin)
436
        self.assertEqual(status, 409)
437

    
438
        # Suspend
439
        status = self.project_action(project_id, "suspend", headers=h_admin)
440
        self.assertEqual(status, 200)
441

    
442
        # Cannot view project
443
        r = client.get(reverse("api_project",
444
                               kwargs={"project_id": project_id}), **h_plain)
445
        self.assertEqual(r.status_code, 403)
446

    
447
        # Unsuspend
448
        status = self.project_action(project_id, "unsuspend", headers=h_admin)
449
        self.assertEqual(status, 200)
450

    
451
        # Cannot approve, project with same name exists
452
        status = self.project_action(project2_id, "approve", project2_app_id,
453
                                     headers=h_admin)
454
        self.assertEqual(status, 409)
455

    
456
        # Terminate
457
        status = self.project_action(project_id, "terminate", headers=h_admin)
458
        self.assertEqual(status, 200)
459

    
460
        # Join failed
461
        status, _ = self.join(project_id, h_admin)
462
        self.assertEqual(status, 409)
463

    
464
        # Can approve now
465
        status = self.project_action(project2_id, "approve", project2_app_id,
466
                                     headers=h_admin)
467
        self.assertEqual(status, 200)
468

    
469
        # Join new project
470
        status, body = self.join(project2_id, h_plain)
471
        self.assertEqual(status, 200)
472
        m_project2 = body["id"]
473

    
474
        # Get memberships of project
475
        filters = {"project": project2_id}
476
        r = client.get(reverse("api_memberships"), filters, **h_owner)
477
        body = json.loads(r.content)
478
        self.assertEqual(len(body), 1)
479
        self.assertEqual(body[0]["id"], m_project2)
480

    
481
        # Remove member
482
        status = self.memb_action(m_project2, "remove", h_owner)
483
        self.assertEqual(status, 200)
484

    
485
        # Reinstate failed
486
        status = self.project_action(project_id, "reinstate", headers=h_admin)
487
        self.assertEqual(status, 409)
488

    
489
        # Rename
490
        app2_renamed = copy.deepcopy(app2)
491
        app2_renamed["name"] = "new.name"
492
        status, body = self.modify(app2_renamed, project_id, h_owner)
493
        self.assertEqual(status, 201)
494
        app2_renamed_id = body["application"]
495

    
496
        # Get project
497
        r = client.get(reverse("api_project",
498
                               kwargs={"project_id": project_id}), **h_owner)
499
        body = json.loads(r.content)
500
        self.assertEqual(body["last_application"]["id"], app2_renamed_id)
501
        self.assertEqual(body["state"], "terminated")
502
        assertIn("deactivation_date", body)
503
        self.assertEqual(body["last_application"]["state"], "pending")
504
        self.assertEqual(body["last_application"]["name"], "new.name")
505
        status = self.project_action(project_id, "approve", app2_renamed_id,
506
                                     headers=h_admin)
507
        self.assertEqual(r.status_code, 200)
508

    
509
        # Change homepage
510
        status, body = self.modify({"homepage": "new.page"},
511
                                   project_id, h_owner)
512
        self.assertEqual(status, 201)
513

    
514
        r = client.get(reverse("api_project",
515
                               kwargs={"project_id": project_id}), **h_owner)
516
        body = json.loads(r.content)
517
        self.assertEqual(body["homepage"], "")
518
        self.assertEqual(body["last_application"]["homepage"], "new.page")
519
        homepage_app = body["last_application"]["id"]
520
        status = self.project_action(project_id, "approve", homepage_app,
521
                                     headers=h_admin)
522
        self.assertEqual(r.status_code, 200)
523
        r = client.get(reverse("api_project",
524
                               kwargs={"project_id": project_id}), **h_owner)
525
        body = json.loads(r.content)
526
        self.assertEqual(body["homepage"], "new.page")
527

    
528
        # Bad requests
529
        r = client.head(reverse("api_projects"), **h_admin)
530
        self.assertEqual(r.status_code, 405)
531
        self.assertTrue('Allow' in r)
532

    
533
        r = client.head(reverse("api_project",
534
                                kwargs={"project_id": 1}), **h_admin)
535
        self.assertEqual(r.status_code, 405)
536
        self.assertTrue('Allow' in r)
537

    
538
        r = client.head(reverse("api_memberships"), **h_admin)
539
        self.assertEqual(r.status_code, 405)
540
        self.assertTrue('Allow' in r)
541

    
542
        status = self.project_action(1, "nonex", headers=h_owner)
543
        self.assertEqual(status, 400)
544

    
545
        action = json.dumps({"suspend": "", "unsuspend": ""})
546
        r = client.post(reverse("api_project_action",
547
                                kwargs={"project_id": 1}),
548
                        action, content_type="application/json", **h_owner)
549
        self.assertEqual(r.status_code, 400)
550

    
551
        ap = {"owner": "nonex",
552
              "join_policy": "nonex",
553
              "leave_policy": "nonex",
554
              "start_date": "nonex",
555
              "homepage": {},
556
              "max_members": -3,
557
              "resources": [],
558
              }
559

    
560
        status, body = self.create(ap, h_owner)
561
        self.assertEqual(status, 400)
562
        self.assertEqual(body["badRequest"]["message"], "User does not exist.")
563

    
564
        ap["owner"] = self.user1.uuid
565
        status, body = self.create(ap, h_owner)
566
        self.assertEqual(status, 400)
567

    
568
        ap["name"] = "some.name"
569
        status, body = self.create(ap, h_owner)
570
        self.assertEqual(status, 400)
571

    
572
        ap["join_policy"] = "auto"
573
        status, body = self.create(ap, h_owner)
574
        self.assertEqual(status, 400)
575

    
576
        ap["leave_policy"] = "closed"
577
        status, body = self.create(ap, h_owner)
578
        self.assertEqual(status, 400)
579

    
580
        ap["start_date"] = "2013-01-01T0:0Z"
581
        status, body = self.create(ap, h_owner)
582
        self.assertEqual(status, 400)
583

    
584
        ap["end_date"] = "2014-01-01T0:0Z"
585
        status, body = self.create(ap, h_owner)
586
        self.assertEqual(status, 400)
587

    
588
        ap["max_members"] = 0
589
        status, body = self.create(ap, h_owner)
590
        self.assertEqual(status, 400)
591

    
592
        ap["homepage"] = "a.stri.ng"
593
        status, body = self.create(ap, h_owner)
594
        self.assertEqual(status, 400)
595

    
596
        ap["resources"] = {42: 42}
597
        status, body = self.create(ap, h_owner)
598
        self.assertEqual(status, 400)
599

    
600
        ap["resources"] = {"service1.resource11": {
601
                "member_capacity": 512}}
602
        status, body = self.create(ap, h_owner)
603
        self.assertEqual(status, 400)
604

    
605
        ap["resources"] = {"service1.resource11": {"member_capacity": 512,
606
                                                   "project_capacity": 1024}}
607
        status, body = self.create(ap, h_owner)
608
        self.assertEqual(status, 201)
609

    
610
        ap["name"] = "non_domain_name"
611
        status, body = self.create(ap, h_owner)
612
        self.assertEqual(status, 400)
613

    
614
        ap["name"] = "domain.name"
615

    
616
        filters = {"state": "nonex"}
617
        r = client.get(reverse("api_projects"), filters, **h_owner)
618
        self.assertEqual(r.status_code, 400)
619

    
620

    
621
class TestProjects(TestCase):
622
    """
623
    Test projects.
624
    """
625
    def setUp(self):
626
        # astakos resources
627
        self.resource = Resource.objects.create(name="astakos.pending_app",
628
                                                uplimit=0,
629
                                                project_default=0,
630
                                                ui_visible=False,
631
                                                api_visible=False,
632
                                                service_type="astakos")
633

    
634
        # custom service resources
635
        self.resource = Resource.objects.create(name="service1.resource",
636
                                                uplimit=100,
637
                                                project_default=0,
638
                                                service_type="service1")
639
        self.admin = get_local_user("projects-admin@synnefo.org")
640
        self.admin.uuid = 'uuid1'
641
        self.admin.save()
642

    
643
        self.user = get_local_user("user@synnefo.org")
644
        self.member = get_local_user("member@synnefo.org")
645
        self.member2 = get_local_user("member2@synnefo.org")
646

    
647
        self.admin_client = get_user_client("projects-admin@synnefo.org")
648
        self.user_client = get_user_client("user@synnefo.org")
649
        self.member_client = get_user_client("member@synnefo.org")
650
        self.member2_client = get_user_client("member2@synnefo.org")
651

    
652
    def tearDown(self):
653
        Service.objects.all().delete()
654
        ProjectApplication.objects.all().delete()
655
        Project.objects.all().delete()
656
        AstakosUser.objects.all().delete()
657

    
658
    @im_settings(PROJECT_ADMINS=['uuid1'])
659
    def test_application_limit(self):
660
        # user cannot create a project
661
        r = self.user_client.get(reverse('project_add'), follow=True)
662
        self.assertRedirects(r, reverse('project_list'))
663
        self.assertContains(r, "You are not allowed to create a new project")
664

    
665
        # but admin can
666
        r = self.admin_client.get(reverse('project_add'), follow=True)
667
        self.assertRedirects(r, reverse('project_add'))
668

    
669
    @im_settings(PROJECT_ADMINS=['uuid1'])
670
    def test_ui_visible(self):
671
        dfrom = datetime.now()
672
        dto = datetime.now() + timedelta(days=30)
673

    
674
        # astakos.pending_app ui_visible flag is False
675
        # we shouldn't be able to create a project application using this
676
        # resource.
677
        application_data = {
678
            'name': 'project.synnefo.org',
679
            'homepage': 'https://www.synnefo.org',
680
            'start_date': dfrom.strftime("%Y-%m-%d"),
681
            'end_date': dto.strftime("%Y-%m-%d"),
682
            'member_join_policy': 2,
683
            'member_leave_policy': 1,
684
            'limit_on_members_number': 5,
685
            'service1.resource_m_uplimit': 100,
686
            'is_selected_service1.resource': "1",
687
            'astakos.pending_app_m_uplimit': 100,
688
            'is_selected_accounts': "1",
689
            'user': self.user.pk
690
        }
691
        form = forms.ProjectApplicationForm(data=application_data)
692
        # form is invalid
693
        self.assertEqual(form.is_valid(), False)
694

    
695
        del application_data['astakos.pending_app_m_uplimit']
696
        del application_data['is_selected_accounts']
697
        form = forms.ProjectApplicationForm(data=application_data)
698
        self.assertEqual(form.is_valid(), True)
699

    
700
    @im_settings(PROJECT_ADMINS=['uuid1'])
701
    def no_test_applications(self):
702
        # let user have 2 pending applications
703

    
704
        # TODO figure this out
705
        request = {"resources": {"astakos.pending_app":
706
                                     {"member_capacity": 2,
707
                                      "project_capacity": 2}}}
708
        functions.modify_project(self.user.uuid, request)
709

    
710
        r = self.user_client.get(reverse('project_add'), follow=True)
711
        self.assertRedirects(r, reverse('project_add'))
712

    
713
        # user fills the project application form
714
        post_url = reverse('project_add') + '?verify=1'
715
        dfrom = datetime.now()
716
        dto = datetime.now() + timedelta(days=30)
717
        application_data = {
718
            'name': 'project.synnefo.org',
719
            'homepage': 'https://www.synnefo.org',
720
            'start_date': dfrom.strftime("%Y-%m-%d"),
721
            'end_date': dto.strftime("%Y-%m-%d"),
722
            'member_join_policy': 2,
723
            'member_leave_policy': 1,
724
            'service1.resource_m_uplimit': 100,
725
            'is_selected_service1.resource': "1",
726
            'user': self.user.pk
727
        }
728
        r = self.user_client.post(post_url, data=application_data, follow=True)
729
        self.assertEqual(r.status_code, 200)
730
        self.assertEqual(r.context['form'].is_valid(), False)
731

    
732
        application_data['limit_on_members_number'] = 5
733
        r = self.user_client.post(post_url, data=application_data, follow=True)
734
        self.assertEqual(r.status_code, 200)
735
        self.assertEqual(r.context['form'].is_valid(), True)
736

    
737
        # confirm request
738
        post_url = reverse('project_add') + '?verify=0&edit=0'
739
        r = self.user_client.post(post_url, data=application_data, follow=True)
740
        self.assertContains(r, "The project application has been received")
741
        self.assertRedirects(r, reverse('project_list'))
742
        self.assertEqual(ProjectApplication.objects.count(), 1)
743
        app1 = ProjectApplication.objects.filter().order_by('pk')[0]
744
        app1_id = app1.pk
745
        project1_id = app1.chain_id
746

    
747
        # create another one
748
        application_data['name'] = 'project2.synnefo.org'
749
        r = self.user_client.post(post_url, data=application_data, follow=True)
750
        app2 = ProjectApplication.objects.filter().order_by('pk')[1]
751
        project2_id = app2.chain_id
752

    
753
        # no more applications (LIMIT is 2)
754
        r = self.user_client.get(reverse('project_add'), follow=True)
755
        self.assertRedirects(r, reverse('project_list'))
756
        self.assertContains(r, "You are not allowed to create a new project")
757

    
758
        # one project per application
759
        self.assertEqual(Project.objects.filter(is_base=False).count(), 2)
760

    
761
        # login
762
        self.admin_client.get(reverse("edit_profile"))
763
        # admin approves
764
        r = self.admin_client.post(reverse('project_app_approve',
765
                                           kwargs={'application_id': app1_id}),
766
                                   follow=True)
767
        self.assertEqual(r.status_code, 200)
768

    
769
        Q_ACTIVE = Project.o_state_q(Project.O_ACTIVE)
770
        self.assertEqual(Project.objects.filter(Q_ACTIVE).count(), 1)
771

    
772
        # login
773
        self.member_client.get(reverse("edit_profile"))
774
        # cannot join project2 (not approved yet)
775
        join_url = reverse("project_join", kwargs={'chain_id': project2_id})
776
        r = self.member_client.post(join_url, follow=True)
777

    
778
        # can join project1
779
        self.member_client.get(reverse("edit_profile"))
780
        join_url = reverse("project_join", kwargs={'chain_id': project1_id})
781
        r = self.member_client.post(join_url, follow=True)
782
        self.assertEqual(r.status_code, 200)
783

    
784
        memberships = ProjectMembership.objects.all()
785
        self.assertEqual(len(memberships), 1)
786
        memb_id = memberships[0].id
787

    
788
        reject_member_url = reverse('project_reject_member',
789
                                    kwargs={'memb_id': memb_id})
790
        accept_member_url = reverse('project_accept_member',
791
                                    kwargs={'memb_id': memb_id})
792

    
793
        # only project owner is allowed to reject
794
        r = self.member_client.post(reject_member_url, follow=True)
795
        self.assertContains(r, "You do not have the permissions")
796
        self.assertEqual(r.status_code, 200)
797

    
798
        # user (owns project) rejects membership
799
        r = self.user_client.post(reject_member_url, follow=True)
800
        self.assertEqual(ProjectMembership.objects.any_accepted().count(), 0)
801

    
802
        # user rejoins
803
        self.member_client.get(reverse("edit_profile"))
804
        join_url = reverse("project_join", kwargs={'chain_id': project1_id})
805
        r = self.member_client.post(join_url, follow=True)
806
        self.assertEqual(r.status_code, 200)
807
        self.assertEqual(ProjectMembership.objects.requested().count(), 1)
808

    
809
        # user (owns project) accepts membership
810
        r = self.user_client.post(accept_member_url, follow=True)
811
        self.assertEqual(ProjectMembership.objects.any_accepted().count(), 1)
812
        membership = ProjectMembership.objects.get()
813
        self.assertEqual(membership.state, ProjectMembership.ACCEPTED)
814

    
815
        user_quotas = quotas.get_users_quotas([self.member])
816
        resource = 'service1.resource'
817
        newlimit = user_quotas[self.member.uuid]['system'][resource]['limit']
818
        # 100 from initial uplimit + 100 from project
819
        self.assertEqual(newlimit, 200)
820

    
821
        remove_member_url = reverse('project_remove_member',
822
                                    kwargs={'memb_id': membership.id})
823
        r = self.user_client.post(remove_member_url, follow=True)
824
        self.assertEqual(r.status_code, 200)
825

    
826
        user_quotas = quotas.get_users_quotas([self.member])
827
        resource = 'service1.resource'
828
        newlimit = user_quotas[self.member.uuid]['system'][resource]['limit']
829
        # 200 - 100 from project
830
        self.assertEqual(newlimit, 100)
831

    
832
        # support email gets rendered in emails content
833
        for mail in get_mailbox('user@synnefo.org'):
834
            self.assertTrue(settings.CONTACT_EMAIL in
835
                            mail.message().as_string())