Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / tests / projects.py @ 1ac3349d

History | View | Annotate | Download (10 kB)

1 1ac3349d Kostas Papadimitriou
# Copyright 2011 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 1ac3349d Kostas Papadimitriou
36 1ac3349d Kostas Papadimitriou
37 1ac3349d Kostas Papadimitriou
class TestProjects(TestCase):
38 1ac3349d Kostas Papadimitriou
    """
39 1ac3349d Kostas Papadimitriou
    Test projects.
40 1ac3349d Kostas Papadimitriou
    """
41 1ac3349d Kostas Papadimitriou
    def setUp(self):
42 1ac3349d Kostas Papadimitriou
        # astakos resources
43 1ac3349d Kostas Papadimitriou
        self.astakos_service = Service.objects.create(name="astakos",
44 1ac3349d Kostas Papadimitriou
                                                      api_url="/astakos/api/")
45 1ac3349d Kostas Papadimitriou
        self.resource = Resource.objects.create(name="astakos.pending_app",
46 1ac3349d Kostas Papadimitriou
                                                uplimit=0,
47 1ac3349d Kostas Papadimitriou
                                                allow_in_projects=False,
48 1ac3349d Kostas Papadimitriou
                                                service=self.astakos_service)
49 1ac3349d Kostas Papadimitriou
50 1ac3349d Kostas Papadimitriou
        # custom service resources
51 1ac3349d Kostas Papadimitriou
        self.service = Service.objects.create(name="service1",
52 1ac3349d Kostas Papadimitriou
                                              api_url="http://service.api")
53 1ac3349d Kostas Papadimitriou
        self.resource = Resource.objects.create(name="service1.resource",
54 1ac3349d Kostas Papadimitriou
                                                uplimit=100,
55 1ac3349d Kostas Papadimitriou
                                                service=self.service)
56 1ac3349d Kostas Papadimitriou
        self.admin = get_local_user("projects-admin@synnefo.org")
57 1ac3349d Kostas Papadimitriou
        self.admin.uuid = 'uuid1'
58 1ac3349d Kostas Papadimitriou
        self.admin.save()
59 1ac3349d Kostas Papadimitriou
60 1ac3349d Kostas Papadimitriou
        self.user = get_local_user("user@synnefo.org")
61 1ac3349d Kostas Papadimitriou
        self.member = get_local_user("member@synnefo.org")
62 1ac3349d Kostas Papadimitriou
        self.member2 = get_local_user("member2@synnefo.org")
63 1ac3349d Kostas Papadimitriou
64 1ac3349d Kostas Papadimitriou
        self.admin_client = get_user_client("projects-admin@synnefo.org")
65 1ac3349d Kostas Papadimitriou
        self.user_client = get_user_client("user@synnefo.org")
66 1ac3349d Kostas Papadimitriou
        self.member_client = get_user_client("member@synnefo.org")
67 1ac3349d Kostas Papadimitriou
        self.member2_client = get_user_client("member2@synnefo.org")
68 1ac3349d Kostas Papadimitriou
69 1ac3349d Kostas Papadimitriou
        quotas.qh_sync_users(AstakosUser.objects.all())
70 1ac3349d Kostas Papadimitriou
71 1ac3349d Kostas Papadimitriou
    @im_settings(PROJECT_ADMINS=['uuid1'])
72 1ac3349d Kostas Papadimitriou
    def test_application_limit(self):
73 1ac3349d Kostas Papadimitriou
        # user cannot create a project
74 1ac3349d Kostas Papadimitriou
        r = self.user_client.get(reverse('project_add'), follow=True)
75 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_list'))
76 1ac3349d Kostas Papadimitriou
        self.assertContains(r, "You are not allowed to create a new project")
77 1ac3349d Kostas Papadimitriou
78 1ac3349d Kostas Papadimitriou
        # but admin can
79 1ac3349d Kostas Papadimitriou
        r = self.admin_client.get(reverse('project_add'), follow=True)
80 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_add'))
81 1ac3349d Kostas Papadimitriou
82 1ac3349d Kostas Papadimitriou
    @im_settings(PROJECT_ADMINS=['uuid1'])
83 1ac3349d Kostas Papadimitriou
    def test_allow_in_project(self):
84 1ac3349d Kostas Papadimitriou
        dfrom = datetime.now()
85 1ac3349d Kostas Papadimitriou
        dto = datetime.now() + timedelta(days=30)
86 1ac3349d Kostas Papadimitriou
87 1ac3349d Kostas Papadimitriou
        # astakos.pending_uplimit allow_in_project flag is False
88 1ac3349d Kostas Papadimitriou
        # we shouldn't be able to create a project application using this
89 1ac3349d Kostas Papadimitriou
        # resource.
90 1ac3349d Kostas Papadimitriou
        application_data = {
91 1ac3349d Kostas Papadimitriou
            'name': 'project.synnefo.org',
92 1ac3349d Kostas Papadimitriou
            'homepage': 'https://www.synnefo.org',
93 1ac3349d Kostas Papadimitriou
            'start_date': dfrom.strftime("%Y-%m-%d"),
94 1ac3349d Kostas Papadimitriou
            'end_date': dto.strftime("%Y-%m-%d"),
95 1ac3349d Kostas Papadimitriou
            'member_join_policy': 2,
96 1ac3349d Kostas Papadimitriou
            'member_leave_policy': 1,
97 1ac3349d Kostas Papadimitriou
            'service1.resource_uplimit': 100,
98 1ac3349d Kostas Papadimitriou
            'is_selected_service1.resource': "1",
99 1ac3349d Kostas Papadimitriou
            'astakos.pending_app_uplimit': 100,
100 1ac3349d Kostas Papadimitriou
            'is_selected_accounts': "1",
101 1ac3349d Kostas Papadimitriou
            'user': self.user.pk
102 1ac3349d Kostas Papadimitriou
        }
103 1ac3349d Kostas Papadimitriou
        form = forms.ProjectApplicationForm(data=application_data)
104 1ac3349d Kostas Papadimitriou
        # form is invalid
105 1ac3349d Kostas Papadimitriou
        self.assertEqual(form.is_valid(), False)
106 1ac3349d Kostas Papadimitriou
107 1ac3349d Kostas Papadimitriou
        del application_data['astakos.pending_app_uplimit']
108 1ac3349d Kostas Papadimitriou
        del application_data['is_selected_accounts']
109 1ac3349d Kostas Papadimitriou
        form = forms.ProjectApplicationForm(data=application_data)
110 1ac3349d Kostas Papadimitriou
        self.assertEqual(form.is_valid(), True)
111 1ac3349d Kostas Papadimitriou
112 1ac3349d Kostas Papadimitriou
    @im_settings(PROJECT_ADMINS=['uuid1'])
113 1ac3349d Kostas Papadimitriou
    def test_applications(self):
114 1ac3349d Kostas Papadimitriou
        # let user have 2 pending applications
115 1ac3349d Kostas Papadimitriou
        quotas.add_base_quota(self.user, 'astakos.pending_app', 2)
116 1ac3349d Kostas Papadimitriou
117 1ac3349d Kostas Papadimitriou
        r = self.user_client.get(reverse('project_add'), follow=True)
118 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_add'))
119 1ac3349d Kostas Papadimitriou
120 1ac3349d Kostas Papadimitriou
        # user fills the project application form
121 1ac3349d Kostas Papadimitriou
        post_url = reverse('project_add') + '?verify=1'
122 1ac3349d Kostas Papadimitriou
        dfrom = datetime.now()
123 1ac3349d Kostas Papadimitriou
        dto = datetime.now() + timedelta(days=30)
124 1ac3349d Kostas Papadimitriou
        application_data = {
125 1ac3349d Kostas Papadimitriou
            'name': 'project.synnefo.org',
126 1ac3349d Kostas Papadimitriou
            'homepage': 'https://www.synnefo.org',
127 1ac3349d Kostas Papadimitriou
            'start_date': dfrom.strftime("%Y-%m-%d"),
128 1ac3349d Kostas Papadimitriou
            'end_date': dto.strftime("%Y-%m-%d"),
129 1ac3349d Kostas Papadimitriou
            'member_join_policy': 2,
130 1ac3349d Kostas Papadimitriou
            'member_leave_policy': 1,
131 1ac3349d Kostas Papadimitriou
            'service1.resource_uplimit': 100,
132 1ac3349d Kostas Papadimitriou
            'is_selected_service1.resource': "1",
133 1ac3349d Kostas Papadimitriou
            'user': self.user.pk
134 1ac3349d Kostas Papadimitriou
        }
135 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(post_url, data=application_data, follow=True)
136 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
137 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.context['form'].is_valid(), True)
138 1ac3349d Kostas Papadimitriou
139 1ac3349d Kostas Papadimitriou
        # confirm request
140 1ac3349d Kostas Papadimitriou
        post_url = reverse('project_add') + '?verify=0&edit=0'
141 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(post_url, data=application_data, follow=True)
142 1ac3349d Kostas Papadimitriou
        self.assertContains(r, "The project application has been received")
143 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_list'))
144 1ac3349d Kostas Papadimitriou
        self.assertEqual(ProjectApplication.objects.count(), 1)
145 1ac3349d Kostas Papadimitriou
        app1_id = ProjectApplication.objects.filter().order_by('pk')[0].pk
146 1ac3349d Kostas Papadimitriou
147 1ac3349d Kostas Papadimitriou
        # create another one
148 1ac3349d Kostas Papadimitriou
        application_data['name'] = 'project2.synnefo.org'
149 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(post_url, data=application_data, follow=True)
150 1ac3349d Kostas Papadimitriou
        app2_id = ProjectApplication.objects.filter().order_by('pk')[1].pk
151 1ac3349d Kostas Papadimitriou
152 1ac3349d Kostas Papadimitriou
        # no more applications (LIMIT is 2)
153 1ac3349d Kostas Papadimitriou
        r = self.user_client.get(reverse('project_add'), follow=True)
154 1ac3349d Kostas Papadimitriou
        self.assertRedirects(r, reverse('project_list'))
155 1ac3349d Kostas Papadimitriou
        self.assertContains(r, "You are not allowed to create a new project")
156 1ac3349d Kostas Papadimitriou
157 1ac3349d Kostas Papadimitriou
        # login
158 1ac3349d Kostas Papadimitriou
        self.admin_client.get(reverse("edit_profile"))
159 1ac3349d Kostas Papadimitriou
        # admin approves
160 1ac3349d Kostas Papadimitriou
        r = self.admin_client.post(reverse('project_app_approve',
161 1ac3349d Kostas Papadimitriou
                                           kwargs={'application_id': app1_id}),
162 1ac3349d Kostas Papadimitriou
                                   follow=True)
163 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
164 1ac3349d Kostas Papadimitriou
165 1ac3349d Kostas Papadimitriou
        # project created
166 1ac3349d Kostas Papadimitriou
        self.assertEqual(Project.objects.count(), 1)
167 1ac3349d Kostas Papadimitriou
168 1ac3349d Kostas Papadimitriou
        # login
169 1ac3349d Kostas Papadimitriou
        self.member_client.get(reverse("edit_profile"))
170 1ac3349d Kostas Papadimitriou
        # cannot join app2 (not approved yet)
171 1ac3349d Kostas Papadimitriou
        join_url = reverse("project_join", kwargs={'chain_id': app2_id})
172 1ac3349d Kostas Papadimitriou
        r = self.member_client.post(join_url, follow=True)
173 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 403)
174 1ac3349d Kostas Papadimitriou
175 1ac3349d Kostas Papadimitriou
        # can join app1
176 1ac3349d Kostas Papadimitriou
        self.member_client.get(reverse("edit_profile"))
177 1ac3349d Kostas Papadimitriou
        join_url = reverse("project_join", kwargs={'chain_id': app1_id})
178 1ac3349d Kostas Papadimitriou
        r = self.member_client.post(join_url, follow=True)
179 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
180 1ac3349d Kostas Papadimitriou
181 1ac3349d Kostas Papadimitriou
        memberships = ProjectMembership.objects.all()
182 1ac3349d Kostas Papadimitriou
        self.assertEqual(len(memberships), 1)
183 1ac3349d Kostas Papadimitriou
        memb_id = memberships[0].id
184 1ac3349d Kostas Papadimitriou
185 1ac3349d Kostas Papadimitriou
        reject_member_url = reverse('project_reject_member',
186 1ac3349d Kostas Papadimitriou
                                    kwargs={'chain_id': app1_id, 'memb_id':
187 1ac3349d Kostas Papadimitriou
                                            memb_id})
188 1ac3349d Kostas Papadimitriou
        accept_member_url = reverse('project_accept_member',
189 1ac3349d Kostas Papadimitriou
                                    kwargs={'chain_id': app1_id, 'memb_id':
190 1ac3349d Kostas Papadimitriou
                                            memb_id})
191 1ac3349d Kostas Papadimitriou
192 1ac3349d Kostas Papadimitriou
        # only project owner is allowed to reject
193 1ac3349d Kostas Papadimitriou
        r = self.member_client.post(reject_member_url, follow=True)
194 1ac3349d Kostas Papadimitriou
        self.assertContains(r, "You do not have the permissions")
195 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
196 1ac3349d Kostas Papadimitriou
197 1ac3349d Kostas Papadimitriou
        # user (owns project) rejects membership
198 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(reject_member_url, follow=True)
199 1ac3349d Kostas Papadimitriou
        self.assertEqual(ProjectMembership.objects.count(), 0)
200 1ac3349d Kostas Papadimitriou
201 1ac3349d Kostas Papadimitriou
        # user rejoins
202 1ac3349d Kostas Papadimitriou
        self.member_client.get(reverse("edit_profile"))
203 1ac3349d Kostas Papadimitriou
        join_url = reverse("project_join", kwargs={'chain_id': app1_id})
204 1ac3349d Kostas Papadimitriou
        r = self.member_client.post(join_url, follow=True)
205 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
206 1ac3349d Kostas Papadimitriou
        self.assertEqual(ProjectMembership.objects.count(), 1)
207 1ac3349d Kostas Papadimitriou
208 1ac3349d Kostas Papadimitriou
        # user (owns project) accepts membership
209 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(accept_member_url, follow=True)
210 1ac3349d Kostas Papadimitriou
        self.assertEqual(ProjectMembership.objects.count(), 1)
211 1ac3349d Kostas Papadimitriou
        membership = ProjectMembership.objects.get()
212 1ac3349d Kostas Papadimitriou
        self.assertEqual(membership.state, ProjectMembership.ACCEPTED)
213 1ac3349d Kostas Papadimitriou
214 1ac3349d Kostas Papadimitriou
        user_quotas = quotas.get_users_quotas([self.member])
215 1ac3349d Kostas Papadimitriou
        resource = 'service1.resource'
216 1ac3349d Kostas Papadimitriou
        newlimit = user_quotas[self.member.uuid]['system'][resource]['limit']
217 1ac3349d Kostas Papadimitriou
        # 100 from initial uplimit + 100 from project
218 1ac3349d Kostas Papadimitriou
        self.assertEqual(newlimit, 200)
219 1ac3349d Kostas Papadimitriou
220 1ac3349d Kostas Papadimitriou
        remove_member_url = reverse('project_remove_member',
221 1ac3349d Kostas Papadimitriou
                                    kwargs={'chain_id': app1_id, 'memb_id':
222 1ac3349d Kostas Papadimitriou
                                            membership.id})
223 1ac3349d Kostas Papadimitriou
        r = self.user_client.post(remove_member_url, follow=True)
224 1ac3349d Kostas Papadimitriou
        self.assertEqual(r.status_code, 200)
225 1ac3349d Kostas Papadimitriou
226 1ac3349d Kostas Papadimitriou
        user_quotas = quotas.get_users_quotas([self.member])
227 1ac3349d Kostas Papadimitriou
        resource = 'service1.resource'
228 1ac3349d Kostas Papadimitriou
        newlimit = user_quotas[self.member.uuid]['system'][resource]['limit']
229 1ac3349d Kostas Papadimitriou
        # 200 - 100 from project
230 1ac3349d Kostas Papadimitriou
        self.assertEqual(newlimit, 100)