Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / im / tests / projects.py @ 50f74340

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