Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / test / stress.py @ f6ff3033

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 django.db import transaction
50
from astakos.im.models import AstakosUser
51
from astakos.im.functions import ProjectError
52
from astakos.im import auth
53
from astakos.im import activation_backends
54
from views import submit, approve, join, leave
55

    
56

    
57
USERS = {}
58
PROJECTS = {}
59

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

    
63

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

    
69

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

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

    
80

    
81
def new_user():
82
    email = random_email()
83
    backend = activation_backends.get_backend()
84
    try:
85
        AstakosUser.objects.get(email=email)
86
        return None
87
    except AstakosUser.DoesNotExist:
88
        u = auth.make_local_user(email, first_name=random_name(),
89
                                 last_name=random_name())
90
        backend.verify_user(u, u.verification_code)
91
        backend.accept_user(u)
92
        return u
93

    
94

    
95
@transaction.commit_on_success
96
def new_users(count):
97
    for i in range(count):
98
        while True:
99
            u = new_user()
100
            if u is not None:
101
                USERS[u.id] = u
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, project_id, 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 for project %s'
125
                        % (prefix, now, project_id))
126
            app_id, project_id = submit(name, user_id, project_id)
127
        except ProjectError as e:
128
            logger.info(e.message)
129
            continue
130
        except Exception as e:
131
            logger.exception(e)
132
            continue
133
        try:
134
            now = datetime.datetime.now()
135
            logger.info('%s%s: approving application %s of project %s'
136
                        % (prefix, now, app_id, project_id))
137
            approve(app_id)
138
            PROJECTS[project_id] = True
139
        except Exception as e:
140
            logger.exception(e)
141

    
142

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

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

    
158

    
159
def join_and_leave(proj_id, user, repeat, prefix=""):
160
    user_id = user.id
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
            membership = join(proj_id, user)
170
        except ProjectError as e:
171
            logger.info(e.message)
172
            continue
173
        except Exception as e:
174
            logger.exception(e)
175
            continue
176
        try:
177
            now = datetime.datetime.now()
178
            logger.info('%s%s: user %s leaving project %s'
179
                        % (prefix, now, user_id, proj_id))
180
            leave(membership.id, user)
181
        except ProjectError as e:
182
            logger.info(e.message)
183
        except Exception as e:
184
            logger.exception(e)
185

    
186

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

    
190
    new_users(users)
191

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

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

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

    
202

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

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

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

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

    
238

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