Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / test / stress.py @ 757f3256

History | View | Annotate | Download (6.8 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
import sys
39
from optparse import OptionParser
40
from time import sleep
41
import threading
42
import datetime
43
from random import choice, randint
44
import logging
45

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

    
50
from astakos.im.api.callpoint import AstakosCallpoint
51
from astakos.im.functions import get_chain_of_application_id
52
from views import submit, approve, join, leave
53
from synnefo.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
77

    
78

    
79
def new_user():
80
    email = random_email()
81
    u = {'email': email,
82
         'first_name': random_name(),
83
         'last_name': random_name(),
84
         'active': True,
85
         }
86
    c = AstakosCallpoint()
87
    r = c.create_users((u,)).next()
88
    return r.data['id'], email
89

    
90

    
91
@commit_on_success_strict()
92
def new_users(count):
93
    for i in range(count):
94
        uid, email = new_user()
95
        USERS[uid] = email
96

    
97

    
98
class SubmitApproveT(threading.Thread):
99
    def __init__(self, *args, **kwargs):
100
        self.repeat = kwargs.pop('repeat', 1)
101
        threading.Thread.__init__(self, *args, **kwargs)
102

    
103
    def run(self):
104
        owner = choice(USERS.keys())
105
        p_name = random_name()
106
        submit_and_approve(p_name, owner, None, self.repeat,
107
                           prefix=self.name)
108

    
109

    
110
def submit_and_approve(name, user_id, prec, repeat, prefix=""):
111
    if prefix:
112
        prefix += ' '
113

    
114
    for i in range(repeat):
115
        try:
116
            now = datetime.datetime.now()
117
            logger.info('%s%s: submitting with precursor %s'
118
                        % (prefix, now, prec))
119
            app_id = submit(name, user_id, prec)
120
            prec = app_id
121
        except Exception as e:
122
            logger.exception(e)
123
        try:
124
            now = datetime.datetime.now()
125
            pid = get_chain_of_application_id(app_id)
126
            logger.info('%s%s: approving application %s of project %s'
127
                        % (prefix, now, app_id, pid))
128
            approve(app_id)
129
            PROJECTS[pid] = True
130
        except Exception as e:
131
            logger.exception(e)
132

    
133

    
134
class JoinLeaveT(threading.Thread):
135
    def __init__(self, *args, **kwargs):
136
        self.repeat = kwargs.pop('repeat', 1)
137
        threading.Thread.__init__(self, *args, **kwargs)
138

    
139
    def run(self):
140
        owner = choice(USERS.keys())
141
        while True:
142
            projects = PROJECTS.keys()
143
            if projects:
144
                pid = choice(projects)
145
                break
146
            sleep(0.1)
147
        join_and_leave(pid, owner, self.repeat, prefix=self.name)
148

    
149

    
150
def join_and_leave(proj_id, user_id, repeat, prefix=""):
151
    if prefix:
152
        prefix += ' '
153

    
154
    for i in range(repeat):
155
        try:
156
            now = datetime.datetime.now()
157
            logger.info('%s%s: user %s joining project %s'
158
                        % (prefix, now, user_id, proj_id))
159
            join(proj_id, user_id)
160
        except Exception as e:
161
            logger.exception(e)
162

    
163
        try:
164
            now = datetime.datetime.now()
165
            logger.info('%s%s: user %s leaving project %s'
166
                        % (prefix, now, user_id, proj_id))
167
            leave(proj_id, user_id)
168
        except Exception as e:
169
            logger.exception(e)
170

    
171

    
172
def test(users, projects, memb, repeat):
173
    logging.basicConfig()
174

    
175
    new_users(users)
176

    
177
    for i in range(projects):
178
        SubmitApproveT(repeat=repeat).start()
179

    
180
    for i in range(memb):
181
        JoinLeaveT(repeat=repeat).start()
182

    
183
    for thread in threading.enumerate():
184
        if thread is not threading.currentThread():
185
            thread.join()
186

    
187

    
188
def main():
189
    parser = OptionParser()
190
    parser.add_option('--users',
191
                      dest='users',
192
                      default=2,
193
                      help="Number of users (default=2)")
194
    parser.add_option('--projects',
195
                      dest='projects',
196
                      default=2,
197
                      help="Number of projects (default=2)")
198
    parser.add_option('--memb',
199
                      dest='memb',
200
                      default=2,
201
                      help="Number of membership requests (default=2)")
202
    parser.add_option('--repeat',
203
                      dest='repeat',
204
                      default=20,
205
                      help="Number of iterations (default=20)")
206
    parser.add_option('-q', '--quiet',
207
                      action='store_true',
208
                      dest='quiet',
209
                      default=False,
210
                      help="Print only errors")
211

    
212
    (options, args) = parser.parse_args()
213

    
214
    if options.quiet:
215
        logger.setLevel(logging.WARNING)
216

    
217
    users = int(options.users)
218
    projects = int(options.projects)
219
    memb = int(options.memb)
220
    repeat = int(options.repeat)
221
    test(users, projects, memb, repeat)
222

    
223

    
224
if __name__ == "__main__":
225
    main()