Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / test / stress.py @ 770dba12

History | View | Annotate | Download (7.4 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 get_chain_of_application_id
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
from django.core.exceptions import PermissionDenied
55

    
56
USERS = {}
57
PROJECTS = {}
58

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

    
62

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

    
68

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

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

    
79

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

    
93

    
94
@commit_on_success_strict()
95
def new_users(count):
96
    for i in range(count):
97
        while True:
98
            result = new_user()
99
            if result is not None:
100
                uid, email = result
101
                USERS[uid] = email
102
                break
103

    
104

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

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

    
116

    
117
def submit_and_approve(name, user_id, prec, repeat, prefix=""):
118
    if prefix:
119
        prefix += ' '
120

    
121
    for i in range(repeat):
122
        try:
123
            now = datetime.datetime.now()
124
            logger.info('%s%s: submitting with precursor %s'
125
                        % (prefix, now, prec))
126
            app_id = submit(name, user_id, prec)
127
            prec = app_id
128
        except PermissionDenied as e:
129
            logger.info('Limit reached')
130
        except Exception as e:
131
            logger.exception(e)
132
            continue
133
        try:
134
            now = datetime.datetime.now()
135
            pid = get_chain_of_application_id(app_id)
136
            logger.info('%s%s: approving application %s of project %s'
137
                        % (prefix, now, app_id, pid))
138
            approve(app_id)
139
            PROJECTS[pid] = True
140
        except Exception as e:
141
            logger.exception(e)
142

    
143

    
144
class JoinLeaveT(threading.Thread):
145
    def __init__(self, *args, **kwargs):
146
        self.repeat = kwargs.pop('repeat', 1)
147
        threading.Thread.__init__(self, *args, **kwargs)
148

    
149
    def run(self):
150
        owner = choice(USERS.keys())
151
        while True:
152
            projects = PROJECTS.keys()
153
            if projects:
154
                pid = choice(projects)
155
                break
156
            sleep(0.1)
157
        join_and_leave(pid, owner, self.repeat, prefix=self.name)
158

    
159

    
160
def join_and_leave(proj_id, user_id, repeat, prefix=""):
161
    if prefix:
162
        prefix += ' '
163

    
164
    for i in range(repeat):
165
        try:
166
            now = datetime.datetime.now()
167
            logger.info('%s%s: user %s joining project %s'
168
                        % (prefix, now, user_id, proj_id))
169
            join(proj_id, user_id)
170
        except PermissionDenied as e:
171
            logger.info('Membership already exists')
172
        except Exception as e:
173
            logger.exception(e)
174

    
175
        try:
176
            now = datetime.datetime.now()
177
            logger.info('%s%s: user %s leaving project %s'
178
                        % (prefix, now, user_id, proj_id))
179
            leave(proj_id, user_id)
180
        except IOError as e:
181
            logger.info('No such membership')
182
        except Exception as e:
183
            logger.exception(e)
184

    
185

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

    
189
    new_users(users)
190

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

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

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

    
201

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

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

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

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

    
237

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