Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / test / stress.py @ 9096ffbb

History | View | Annotate | Download (7.3 kB)

1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3

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

    
37
import os
38
from optparse import OptionParser
39
from time import sleep
40
import threading
41
import datetime
42
from random import choice, randint
43
import logging
44

    
45
path = os.path.dirname(os.path.realpath(__file__))
46
os.environ['SYNNEFO_SETTINGS_DIR'] = path + '/settings'
47
os.environ['DJANGO_SETTINGS_MODULE'] = 'synnefo.settings'
48

    
49
from astakos.im.models import AstakosUser
50
from astakos.im.functions import ProjectError
51
from astakos.im import quotas
52
from views import submit, approve, join, leave
53
from snf_django.lib.db.transaction import commit_on_success_strict
54

    
55
USERS = {}
56
PROJECTS = {}
57

    
58
logger = logging.getLogger(__name__)
59
logger.setLevel(logging.INFO)
60

    
61

    
62
def random_name():
63
    alphabet = u'abcdef_123490αβγδεζ'
64
    length = randint(1, 15)
65
    return ''.join(choice(alphabet) for _ in xrange(length))
66

    
67

    
68
def random_email():
69
    alphabet = u'abcdef_123490'
70
    length = randint(1, 10)
71
    first = ''.join(choice(alphabet) for _ in xrange(length))
72

    
73
    alphabet = u'abcdef'
74
    length = randint(2, 4)
75
    last = ''.join(choice(alphabet) for _ in xrange(length))
76
    return first + '@' + last + '.com'
77

    
78

    
79
def new_user():
80
    email = random_email()
81
    defaults = {'first_name': random_name(),
82
                'last_name': random_name(),
83
                'is_active': True,
84
                }
85
    u, created = AstakosUser.objects.get_or_create(
86
        email=email, defaults=defaults)
87
    if created:
88
        quotas.qh_sync_user(u)
89
        return u
90
    return None
91

    
92

    
93
@commit_on_success_strict()
94
def new_users(count):
95
    for i in range(count):
96
        while True:
97
            u = new_user()
98
            if u is not None:
99
                USERS[u.id] = u
100
                break
101

    
102

    
103
class SubmitApproveT(threading.Thread):
104
    def __init__(self, *args, **kwargs):
105
        self.repeat = kwargs.pop('repeat', 1)
106
        threading.Thread.__init__(self, *args, **kwargs)
107

    
108
    def run(self):
109
        owner = choice(USERS.keys())
110
        p_name = random_name()
111
        submit_and_approve(p_name, owner, None, self.repeat,
112
                           prefix=self.name)
113

    
114

    
115
def submit_and_approve(name, user_id, project_id, repeat, prefix=""):
116
    if prefix:
117
        prefix += ' '
118

    
119
    for i in range(repeat):
120
        try:
121
            now = datetime.datetime.now()
122
            logger.info('%s%s: submitting for project %s'
123
                        % (prefix, now, project_id))
124
            app_id, project_id = submit(name, user_id, project_id)
125
        except ProjectError as e:
126
            logger.info(e.message)
127
            continue
128
        except Exception as e:
129
            logger.exception(e)
130
            continue
131
        try:
132
            now = datetime.datetime.now()
133
            logger.info('%s%s: approving application %s of project %s'
134
                        % (prefix, now, app_id, project_id))
135
            approve(app_id)
136
            PROJECTS[project_id] = True
137
        except Exception as e:
138
            logger.exception(e)
139

    
140

    
141
class JoinLeaveT(threading.Thread):
142
    def __init__(self, *args, **kwargs):
143
        self.repeat = kwargs.pop('repeat', 1)
144
        threading.Thread.__init__(self, *args, **kwargs)
145

    
146
    def run(self):
147
        user = choice(USERS.values())
148
        while True:
149
            projects = PROJECTS.keys()
150
            if projects:
151
                pid = choice(projects)
152
                break
153
            sleep(0.1)
154
        join_and_leave(pid, user, self.repeat, prefix=self.name)
155

    
156

    
157
def join_and_leave(proj_id, user, repeat, prefix=""):
158
    user_id = user.id
159
    if prefix:
160
        prefix += ' '
161

    
162
    for i in range(repeat):
163
        try:
164
            now = datetime.datetime.now()
165
            logger.info('%s%s: user %s joining project %s'
166
                        % (prefix, now, user_id, proj_id))
167
            membership = join(proj_id, user)
168
        except ProjectError as e:
169
            logger.info(e.message)
170
            continue
171
        except Exception as e:
172
            logger.exception(e)
173
            continue
174
        try:
175
            now = datetime.datetime.now()
176
            logger.info('%s%s: user %s leaving project %s'
177
                        % (prefix, now, user_id, proj_id))
178
            leave(membership.id, user)
179
        except ProjectError as e:
180
            logger.info(e.message)
181
        except Exception as e:
182
            logger.exception(e)
183

    
184

    
185
def test(users, projects, memb, repeat):
186
    logging.basicConfig()
187

    
188
    new_users(users)
189

    
190
    for i in range(projects):
191
        SubmitApproveT(repeat=repeat).start()
192

    
193
    for i in range(memb):
194
        JoinLeaveT(repeat=repeat).start()
195

    
196
    for thread in threading.enumerate():
197
        if thread is not threading.currentThread():
198
            thread.join()
199

    
200

    
201
def main():
202
    parser = OptionParser()
203
    parser.add_option('--users',
204
                      dest='users',
205
                      default=2,
206
                      help="Number of users (default=2)")
207
    parser.add_option('--projects',
208
                      dest='projects',
209
                      default=2,
210
                      help="Number of projects (default=2)")
211
    parser.add_option('--memb',
212
                      dest='memb',
213
                      default=2,
214
                      help="Number of membership requests (default=2)")
215
    parser.add_option('--repeat',
216
                      dest='repeat',
217
                      default=20,
218
                      help="Number of iterations (default=20)")
219
    parser.add_option('-q', '--quiet',
220
                      action='store_true',
221
                      dest='quiet',
222
                      default=False,
223
                      help="Print only errors")
224

    
225
    (options, args) = parser.parse_args()
226

    
227
    if options.quiet:
228
        logger.setLevel(logging.WARNING)
229

    
230
    users = int(options.users)
231
    projects = int(options.projects)
232
    memb = int(options.memb)
233
    repeat = int(options.repeat)
234
    test(users, projects, memb, repeat)
235

    
236

    
237
if __name__ == "__main__":
238
    main()