Statistics
| Branch: | Tag: | Revision:

root / snf-astakos-app / astakos / test / stress.py @ 84a1d7dd

History | View | Annotate | Download (6.7 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

    
54
USERS = {}
55
PROJECTS = {}
56

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

    
60

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

    
66

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

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

    
77

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

    
89

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

    
95

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

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

    
107

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

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

    
131

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

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

    
147

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

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

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

    
169

    
170
def test(users, projects, memb, repeat):
171
    logging.basicConfig()
172

    
173
    new_users(users)
174

    
175
    for i in range(projects):
176
        SubmitApproveT(repeat=repeat).start()
177

    
178
    for i in range(memb):
179
        JoinLeaveT(repeat=repeat).start()
180

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

    
185

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

    
210
    (options, args) = parser.parse_args()
211

    
212
    if options.quiet:
213
        logger.setLevel(logging.WARNING)
214

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

    
221

    
222
if __name__ == "__main__":
223
    main()