added benchmarking
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@@ -1,6 +1,7 @@
 | 
				
			|||||||
# project specific
 | 
					# project specific
 | 
				
			||||||
settings.json
 | 
					settings.json
 | 
				
			||||||
db.sqlite3
 | 
					db.sqlite3
 | 
				
			||||||
 | 
					*.prof
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Byte-compiled / optimized / DLL files
 | 
					# Byte-compiled / optimized / DLL files
 | 
				
			||||||
__pycache__/
 | 
					__pycache__/
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -80,6 +80,12 @@ DEBUG_TOOLBAR_PANELS = [
 | 
				
			|||||||
########################################################################
 | 
					########################################################################
 | 
				
			||||||
##                    DERUG                                           ##
 | 
					##                    DERUG                                           ##
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# SILKY_PYTHON_PROFILER = True
 | 
				
			||||||
 | 
					# SILKY_PYTHON_PROFILER_BINARY = True
 | 
				
			||||||
 | 
					# SILKY_PYTHON_PROFILER_RESULT_PATH = BASE_DIR + "/profiler"
 | 
				
			||||||
 | 
					# SILKY_META = True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
LOGIN_REDIRECT_URL = '/books'
 | 
					LOGIN_REDIRECT_URL = '/books'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Application definition
 | 
					# Application definition
 | 
				
			||||||
@@ -92,14 +98,14 @@ INSTALLED_APPS = [
 | 
				
			|||||||
    'django.contrib.messages',
 | 
					    'django.contrib.messages',
 | 
				
			||||||
    'django.contrib.staticfiles',
 | 
					    'django.contrib.staticfiles',
 | 
				
			||||||
    "library",
 | 
					    "library",
 | 
				
			||||||
    # "silk",
 | 
					    # "silk", # DEBUG/profilling purposes
 | 
				
			||||||
    # 'debug_toolbar', # DEBUG  purposes
 | 
					    # 'debug_toolbar', # DEBUG  purposes
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
MIDDLEWARE = [
 | 
					MIDDLEWARE = [
 | 
				
			||||||
    # 'silk.middleware.SilkyMiddleware', # DEBUG/profiling purposes
 | 
					    # 'silk.middleware.SilkyMiddleware', # DEBUG/profiling purposes
 | 
				
			||||||
    # 'debug_toolbar.middleware.DebugToolbarMiddleware', # DEBUG purposes
 | 
					    # 'debug_toolbar.middleware.DebugToolbarMiddleware', # DEBUG purposes
 | 
				
			||||||
    'django.middleware.cache.UpdateCacheMiddleware', # cache
 | 
					    # 'django.middleware.cache.UpdateCacheMiddleware', # cache
 | 
				
			||||||
    'django.middleware.security.SecurityMiddleware',
 | 
					    'django.middleware.security.SecurityMiddleware',
 | 
				
			||||||
    'django.contrib.sessions.middleware.SessionMiddleware',
 | 
					    'django.contrib.sessions.middleware.SessionMiddleware',
 | 
				
			||||||
    'django.middleware.common.CommonMiddleware',
 | 
					    'django.middleware.common.CommonMiddleware',
 | 
				
			||||||
@@ -107,8 +113,11 @@ MIDDLEWARE = [
 | 
				
			|||||||
    'django.contrib.auth.middleware.AuthenticationMiddleware',
 | 
					    'django.contrib.auth.middleware.AuthenticationMiddleware',
 | 
				
			||||||
    'django.contrib.messages.middleware.MessageMiddleware',
 | 
					    'django.contrib.messages.middleware.MessageMiddleware',
 | 
				
			||||||
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
 | 
					    'django.middleware.clickjacking.XFrameOptionsMiddleware',
 | 
				
			||||||
    'django.middleware.cache.FetchFromCacheMiddleware', # cache
 | 
					    # 'django.middleware.cache.FetchFromCacheMiddleware', # cache
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
 | 
					##                                                                    ##
 | 
				
			||||||
 | 
					########################################################################
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ROOT_URLCONF = 'CalibreWebCompanion.urls'
 | 
					ROOT_URLCONF = 'CalibreWebCompanion.urls'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -22,6 +22,7 @@ from django.conf import settings
 | 
				
			|||||||
from django.urls import include, path
 | 
					from django.urls import include, path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
urlpatterns = [
 | 
					urlpatterns = [
 | 
				
			||||||
    path('admin/', admin.site.urls),
 | 
					    path('admin/', admin.site.urls),
 | 
				
			||||||
    path('accounts/', include('django.contrib.auth.urls')),
 | 
					    path('accounts/', include('django.contrib.auth.urls')),
 | 
				
			||||||
@@ -31,7 +32,7 @@ urlpatterns = [
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# if settings.DEBUG: # DEBUG purposes
 | 
					# if settings.DEBUG: # DEBUG purposes
 | 
				
			||||||
    # urlpatterns+= [path('silk/', include('silk.urls', namespace='silk'))]
 | 
					#     urlpatterns+= [path('silk/', include('silk.urls', namespace='silk'))]
 | 
				
			||||||
    # import debug_toolbar
 | 
					    # import debug_toolbar
 | 
				
			||||||
    # urlpatterns = [
 | 
					    # urlpatterns = [
 | 
				
			||||||
    #     path('__debug__/', include(debug_toolbar.urls)),
 | 
					    #     path('__debug__/', include(debug_toolbar.urls)),
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -10,19 +10,20 @@ urlpatterns = [
 | 
				
			|||||||
    path('ratings/', views.RatingListView.as_view(), name='ratings'),
 | 
					    path('ratings/', views.RatingListView.as_view(), name='ratings'),
 | 
				
			||||||
    path('tags/', views.TagListView.as_view(), name='tags'),
 | 
					    path('tags/', views.TagListView.as_view(), name='tags'),
 | 
				
			||||||
    path('series/', views.SeriesListView.as_view(), name='series'),
 | 
					    path('series/', views.SeriesListView.as_view(), name='series'),
 | 
				
			||||||
 | 
					    path('author/<int:pk>', views.AuthorDetailView.as_view(),
 | 
				
			||||||
 | 
					         name='author-detail-view'),
 | 
				
			||||||
    path('author/<int:pk>', views.AuthorDetailView.as_view(), name='author-detail-view'),
 | 
					 | 
				
			||||||
    path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail-view'),
 | 
					    path('book/<int:pk>', views.BookDetailView.as_view(), name='book-detail-view'),
 | 
				
			||||||
    path('publisher/<int:pk>', views.PublisherDetailView.as_view(), name='publisher-detail-view'),
 | 
					    path('publisher/<int:pk>', views.PublisherDetailView.as_view(),
 | 
				
			||||||
    path('rating/<int:pk>', views.RatingDetailView.as_view(), name='rating-detail-view'),
 | 
					         name='publisher-detail-view'),
 | 
				
			||||||
    path('series/<int:pk>', views.SeriesDetailView.as_view(), name='series-detail-view'),
 | 
					    path('rating/<int:pk>', views.RatingDetailView.as_view(),
 | 
				
			||||||
 | 
					         name='rating-detail-view'),
 | 
				
			||||||
 | 
					    path('series/<int:pk>', views.SeriesDetailView.as_view(),
 | 
				
			||||||
 | 
					         name='series-detail-view'),
 | 
				
			||||||
    path('tag/<int:pk>', views.TagDetailView.as_view(), name='tag-detail-view'),
 | 
					    path('tag/<int:pk>', views.TagDetailView.as_view(), name='tag-detail-view'),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    path('results/', views.ResultsView.as_view(), name='results'),
 | 
					    path('results/', views.ResultsView.as_view(), name='results'),
 | 
				
			||||||
    path('search/', views.SearchView.as_view(), name='search'),
 | 
					    path('search/', views.SearchView.as_view(), name='search'),
 | 
				
			||||||
 | 
					    path('accounts/sign_up/', views.sign_up, name="sign-up")
 | 
				
			||||||
    path('accounts/sign_up/',views.sign_up,name="sign-up")
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
]
 | 
					]
 | 
				
			||||||
@@ -10,6 +10,9 @@ from django.contrib.auth import login
 | 
				
			|||||||
from django.contrib.auth.decorators import login_required
 | 
					from django.contrib.auth.decorators import login_required
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# might be helpful for vary headers later
 | 
				
			||||||
 | 
					from django.utils.decorators import method_decorator
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@login_required
 | 
					@login_required
 | 
				
			||||||
def index(request):
 | 
					def index(request):
 | 
				
			||||||
@@ -31,6 +34,9 @@ def sign_up(request):
 | 
				
			|||||||
class SearchView(generic.TemplateView):
 | 
					class SearchView(generic.TemplateView):
 | 
				
			||||||
    template_name = 'search.html'
 | 
					    template_name = 'search.html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(SearchView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ResultsView(generic.ListView):  # no clue if this is secure.
 | 
					class ResultsView(generic.ListView):  # no clue if this is secure.
 | 
				
			||||||
    # according to this https://stackoverflow.com/questions/13574043/how-do-django-forms-sanitize-text-input-to-prevent-sql-injection-xss-etc
 | 
					    # according to this https://stackoverflow.com/questions/13574043/how-do-django-forms-sanitize-text-input-to-prevent-sql-injection-xss-etc
 | 
				
			||||||
@@ -38,6 +44,9 @@ class ResultsView(generic.ListView):  # no clue if this is secure.
 | 
				
			|||||||
    model = Book
 | 
					    model = Book
 | 
				
			||||||
    template_name = 'results.html'
 | 
					    template_name = 'results.html'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(ResultsView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self):  # new
 | 
					    def get_queryset(self):  # new
 | 
				
			||||||
        title = self.request.GET.get('title')
 | 
					        title = self.request.GET.get('title')
 | 
				
			||||||
        author = self.request.GET.get('author')
 | 
					        author = self.request.GET.get('author')
 | 
				
			||||||
@@ -62,10 +71,16 @@ class ResultsView(generic.ListView):  # no clue if this is secure.
 | 
				
			|||||||
class AuthorListView(generic.ListView):
 | 
					class AuthorListView(generic.ListView):
 | 
				
			||||||
    model = Author
 | 
					    model = Author
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(AuthorListView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class BookListView(generic.ListView):
 | 
					class BookListView(generic.ListView):
 | 
				
			||||||
    model = Book
 | 
					    model = Book
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(BookListView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_queryset(self):
 | 
					    def get_queryset(self):
 | 
				
			||||||
        # Annotate the books with ratings, tags, etc
 | 
					        # Annotate the books with ratings, tags, etc
 | 
				
			||||||
        # books = Book.objects.annotate(
 | 
					        # books = Book.objects.annotate(
 | 
				
			||||||
@@ -76,21 +91,37 @@ class BookListView(generic.ListView):
 | 
				
			|||||||
class PublisherListView(generic.ListView):
 | 
					class PublisherListView(generic.ListView):
 | 
				
			||||||
    model = Publisher
 | 
					    model = Publisher
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(PublisherListView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class RatingListView(generic.ListView):
 | 
					class RatingListView(generic.ListView):
 | 
				
			||||||
    model = Rating
 | 
					    model = Rating
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SeriesListView(generic.ListView): # make url entry and template, sometime
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(RatingListView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class SeriesListView(generic.ListView):  # make url entry and template, sometime
 | 
				
			||||||
    model = Series
 | 
					    model = Series
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(SeriesListView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class TagListView(generic.ListView):
 | 
					class TagListView(generic.ListView):
 | 
				
			||||||
    model = Tag
 | 
					    model = Tag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(TagListView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class AuthorDetailView(generic.DetailView):
 | 
					class AuthorDetailView(generic.DetailView):
 | 
				
			||||||
    model = Author
 | 
					    model = Author
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(AuthorDetailView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        # Call the base implementation first to get the context
 | 
					        # Call the base implementation first to get the context
 | 
				
			||||||
        context = super(AuthorDetailView, self).get_context_data(**kwargs)
 | 
					        context = super(AuthorDetailView, self).get_context_data(**kwargs)
 | 
				
			||||||
@@ -104,6 +135,9 @@ class AuthorDetailView(generic.DetailView):
 | 
				
			|||||||
class BookDetailView(generic.DetailView):
 | 
					class BookDetailView(generic.DetailView):
 | 
				
			||||||
    model = Book
 | 
					    model = Book
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(BookDetailView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        # Call the base implementation first to get the context
 | 
					        # Call the base implementation first to get the context
 | 
				
			||||||
        context = super(BookDetailView, self).get_context_data(**kwargs)
 | 
					        context = super(BookDetailView, self).get_context_data(**kwargs)
 | 
				
			||||||
@@ -122,6 +156,9 @@ class BookDetailView(generic.DetailView):
 | 
				
			|||||||
class PublisherDetailView(generic.DetailView):
 | 
					class PublisherDetailView(generic.DetailView):
 | 
				
			||||||
    model = Publisher
 | 
					    model = Publisher
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(PublisherDetailView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        # Call the base implementation first to get the context
 | 
					        # Call the base implementation first to get the context
 | 
				
			||||||
        context = super(PublisherDetailView, self).get_context_data(**kwargs)
 | 
					        context = super(PublisherDetailView, self).get_context_data(**kwargs)
 | 
				
			||||||
@@ -135,6 +172,9 @@ class PublisherDetailView(generic.DetailView):
 | 
				
			|||||||
class RatingDetailView(generic.DetailView):
 | 
					class RatingDetailView(generic.DetailView):
 | 
				
			||||||
    model = Rating
 | 
					    model = Rating
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(RatingDetailView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        # Call the base implementation first to get the context
 | 
					        # Call the base implementation first to get the context
 | 
				
			||||||
        context = super(RatingDetailView, self).get_context_data(**kwargs)
 | 
					        context = super(RatingDetailView, self).get_context_data(**kwargs)
 | 
				
			||||||
@@ -148,6 +188,9 @@ class RatingDetailView(generic.DetailView):
 | 
				
			|||||||
class TagDetailView(generic.DetailView):
 | 
					class TagDetailView(generic.DetailView):
 | 
				
			||||||
    model = Tag
 | 
					    model = Tag
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(TagDetailView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        # Call the base implementation first to get the context
 | 
					        # Call the base implementation first to get the context
 | 
				
			||||||
        context = super(TagDetailView, self).get_context_data(**kwargs)
 | 
					        context = super(TagDetailView, self).get_context_data(**kwargs)
 | 
				
			||||||
@@ -157,9 +200,13 @@ class TagDetailView(generic.DetailView):
 | 
				
			|||||||
        context['books'] = sorted(books,  key=lambda x: x.title)
 | 
					        context['books'] = sorted(books,  key=lambda x: x.title)
 | 
				
			||||||
        return context
 | 
					        return context
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class SeriesDetailView(generic.DetailView):
 | 
					class SeriesDetailView(generic.DetailView):
 | 
				
			||||||
    model = Series
 | 
					    model = Series
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def dispatch(self, *args, **kwargs):
 | 
				
			||||||
 | 
					        return super(SeriesDetailView, self).dispatch(*args, **kwargs)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def get_context_data(self, **kwargs):
 | 
					    def get_context_data(self, **kwargs):
 | 
				
			||||||
        # Call the base implementation first to get the context
 | 
					        # Call the base implementation first to get the context
 | 
				
			||||||
        context = super(SeriesDetailView, self).get_context_data(**kwargs)
 | 
					        context = super(SeriesDetailView, self).get_context_data(**kwargs)
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										22
									
								
								loadtesting/bench.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								loadtesting/bench.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,22 @@
 | 
				
			|||||||
 | 
					import csv
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def floatify(mystring):  # floatify probable floats
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        return f"{float(mystring):3.3f}"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					results = dict() 
 | 
				
			||||||
 | 
					with open("calibre_stats.csv", "r") as cfile:
 | 
				
			||||||
 | 
					    reader = csv.reader(cfile, delimiter=",")
 | 
				
			||||||
 | 
					    for row in reader:
 | 
				
			||||||
 | 
					        if not len(row):
 | 
				
			||||||
 | 
					            continue
 | 
				
			||||||
 | 
					        results[action] = {
 | 
				
			||||||
 | 
					            "median" : floatify(row[4]),
 | 
				
			||||||
 | 
					            "avg" : floatify(row[5]),
 | 
				
			||||||
 | 
					            "min" : floatify(row[6]),
 | 
				
			||||||
 | 
					            "max" : floatify(row[7]),
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										2
									
								
								loadtesting/calibre_failures.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								loadtesting/calibre_failures.csv
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					Method,Name,Error,Occurrences
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		
		
			
  | 
							
								
								
									
										20
									
								
								loadtesting/calibre_stats.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								loadtesting/calibre_stats.csv
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,20 @@
 | 
				
			|||||||
 | 
					Type,Name,Request Count,Failure Count,Median Response Time,Average Response Time,Min Response Time,Max Response Time,Average Content Size,Requests/s,Failures/s,50%,66%,75%,80%,90%,95%,98%,99%,99.9%,99.99%,99.999%,100%
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GET,/accounts/login/,20,0,48,65.55451154708862,14.944314956665039,260.83922386169434,2024.0,0.16925718599032696,0.0,53,60,79,82,180,260,260,260,260,260,260,260
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					POST,/accounts/login/,20,0,500.0,563.2974982261658,342.44489669799805,988.3866310119629,68954.9,0.16925718599032696,0.0,520,630,680,770,860,990,990,990,990,990,990,990
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GET,/author/<id>,32,0,42,66.19161367416382,20.987987518310547,389.75977897644043,23424.375,0.2708114975845231,0.0,42,55,79,83,110,240,390,390,390,390,390,390
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GET,/authors/,36,0,52,63.24449512693617,13.991117477416992,158.9028835296631,38376.63888888889,0.30466293478258855,0.0,56,70,76,76,99,150,160,160,160,160,160,160
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GET,/book/<id>,91,3,57,71.04945968795609,19.988059997558594,273.82922172546387,31187.23076923077,0.7701201962559876,0.025388577898549043,57,72,87,90,130,170,230,270,270,270,270,270
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GET,/books/,53,0,180.0,190.23628504771108,9.994029998779297,504.6887397766113,68252.92452830188,0.4485315428743664,0.0,180,200,220,240,270,410,480,500,500,500,500,500
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GET,/publisher/<id>,19,0,46,62.593510276392884,22.986173629760742,190.87886810302734,29474.105263157893,0.16079432669081062,0.0,46,60,85,87,150,190,190,190,190,190,190,190
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GET,/publishers/,22,0,41,52.96537009152499,9.990453720092773,127.92515754699707,30564.363636363636,0.18618290458935965,0.0,45,55,71,78,110,110,130,130,130,130,130,130
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GET,/rating/<id>,47,0,56,69.93506817107505,28.981924057006836,293.81442070007324,33666.68085106383,0.39775438707726835,0.0,56,71,89,95,110,140,290,290,290,290,290,290
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		
		
			
  | 
							
								
								
									
										61
									
								
								loadtesting/calibre_stats_history.csv
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								loadtesting/calibre_stats_history.csv
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,61 @@
 | 
				
			|||||||
 | 
					"Timestamp","User Count","Type","Name","Requests/s","Failures/s","50%","66%","75%","80%","90%","95%","98%","99%","99.9%","99.99%","99.999%","100%","Total Request Count","Total Failure Count","Total Median Response Time","Total Average Response Time","Total Min Response Time","Total Max Response Time","Total Average Content Size"
 | 
				
			||||||
 | 
					"1594955401","1","","Aggregated",0.00,0.00,"N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A","N/A",0,0,0,0,0,0,0
 | 
				
			||||||
 | 
					"1594955403","5","","Aggregated",0.00,0.00,30,390,410,410,450,450,450,450,450,450,450,450,12,0,26,152,10,450,19557
 | 
				
			||||||
 | 
					"1594955405","9","","Aggregated",5.00,0.00,31,48,360,380,410,450,470,470,470,470,470,470,25,0,31,135,10,470,25208
 | 
				
			||||||
 | 
					"1594955407","13","","Aggregated",5.75,0.00,48,72,380,390,490,770,780,780,780,780,780,780,40,0,45,169,10,779,29961
 | 
				
			||||||
 | 
					"1594955409","17","","Aggregated",6.17,0.00,64,260,380,410,500,780,860,990,990,990,990,990,57,0,64,210,10,988,31323
 | 
				
			||||||
 | 
					"1594955411","20","","Aggregated",6.38,0.00,60,180,370,410,610,770,860,990,990,990,990,990,79,0,60,198,10,988,31968
 | 
				
			||||||
 | 
					"1594955413","20","","Aggregated",7.00,0.00,56,140,260,370,610,770,860,990,990,990,990,990,92,0,53,182,10,988,32493
 | 
				
			||||||
 | 
					"1594955415","20","","Aggregated",7.90,0.00,55,110,200,260,530,680,860,990,990,990,990,990,107,0,53,166,10,988,32284
 | 
				
			||||||
 | 
					"1594955417","20","","Aggregated",8.00,0.00,51,95,150,180,520,630,860,990,990,990,990,990,119,0,51,153,10,988,32032
 | 
				
			||||||
 | 
					"1594955419","20","","Aggregated",7.90,0.00,43,53,91,110,170,520,630,630,630,630,630,630,133,0,49,143,10,988,32464
 | 
				
			||||||
 | 
					"1594955421","20","","Aggregated",7.70,0.00,43,55,73,85,120,160,190,240,240,240,240,240,147,0,50,136,10,988,32634
 | 
				
			||||||
 | 
					"1594955423","20","","Aggregated",7.50,0.00,41,53,70,75,110,160,190,240,240,240,240,240,158,0,49,129,10,988,32266
 | 
				
			||||||
 | 
					"1594955425","20","","Aggregated",6.40,0.00,39,50,56,70,110,160,170,190,190,190,190,190,173,0,48,123,9,988,32582
 | 
				
			||||||
 | 
					"1594955427","20","","Aggregated",6.40,0.00,43,56,74,87,150,160,170,190,190,190,190,190,185,0,48,120,9,988,33041
 | 
				
			||||||
 | 
					"1594955429","20","","Aggregated",6.60,0.00,41,55,70,78,150,160,160,170,170,170,170,170,199,0,48,115,9,988,32717
 | 
				
			||||||
 | 
					"1594955431","20","","Aggregated",6.60,0.00,38,52,59,70,120,160,160,170,170,170,170,170,211,0,45,111,9,988,32736
 | 
				
			||||||
 | 
					"1594955433","20","","Aggregated",6.30,0.00,38,45,54,59,110,150,160,170,170,170,170,170,224,0,43,106,9,988,32289
 | 
				
			||||||
 | 
					"1594955435","20","","Aggregated",6.50,0.00,42,55,72,85,150,170,170,190,190,190,190,190,235,0,45,106,9,988,32805
 | 
				
			||||||
 | 
					"1594955437","20","","Aggregated",6.40,0.00,38,51,59,70,95,160,170,190,190,190,190,190,246,0,45,104,9,988,32821
 | 
				
			||||||
 | 
					"1594955439","20","","Aggregated",6.10,0.00,36,54,65,71,130,170,190,200,200,200,200,200,260,0,45,101,9,988,32811
 | 
				
			||||||
 | 
					"1594955441","20","","Aggregated",5.90,0.00,47,60,71,72,150,180,190,200,200,200,200,200,272,0,45,99,9,988,32809
 | 
				
			||||||
 | 
					"1594955443","20","","Aggregated",6.10,0.00,52,65,72,81,150,180,190,200,200,200,200,200,284,1,45,97,9,988,32796
 | 
				
			||||||
 | 
					"1594955445","20","","Aggregated",6.30,0.10,49,60,66,72,100,160,200,210,210,210,210,210,297,1,46,96,9,988,32829
 | 
				
			||||||
 | 
					"1594955447","20","","Aggregated",6.10,0.10,51,65,74,92,130,180,200,210,210,210,210,210,310,1,46,95,9,988,32921
 | 
				
			||||||
 | 
					"1594955449","20","","Aggregated",6.00,0.10,46,55,66,80,130,140,190,210,210,210,210,210,326,1,45,92,8,988,32638
 | 
				
			||||||
 | 
					"1594955451","20","","Aggregated",7.00,0.10,44,55,74,83,130,170,190,210,210,210,210,210,339,1,45,91,8,988,32716
 | 
				
			||||||
 | 
					"1594955453","20","","Aggregated",6.80,0.10,42,57,82,88,140,180,190,210,210,210,210,210,356,1,45,90,8,988,32851
 | 
				
			||||||
 | 
					"1594955455","20","","Aggregated",6.70,0.00,41,57,82,88,140,190,190,210,210,210,210,210,370,1,45,89,8,988,33034
 | 
				
			||||||
 | 
					"1594955457","20","","Aggregated",7.00,0.00,38,56,63,82,120,180,190,210,210,210,210,210,386,1,45,88,8,988,32931
 | 
				
			||||||
 | 
					"1594955459","20","","Aggregated",7.30,0.00,45,63,82,88,130,180,190,210,210,210,210,210,399,1,45,87,8,988,32863
 | 
				
			||||||
 | 
					"1594955461","20","","Aggregated",7.00,0.00,45,62,74,93,140,160,190,210,210,210,210,210,414,1,45,86,8,988,32948
 | 
				
			||||||
 | 
					"1594955463","20","","Aggregated",6.70,0.00,57,72,96,110,140,190,220,260,260,260,260,260,429,1,46,87,8,988,33186
 | 
				
			||||||
 | 
					"1594955466","20","","Aggregated",7.30,0.00,58,72,93,110,140,160,220,260,260,260,260,260,441,1,45,85,8,988,33061
 | 
				
			||||||
 | 
					"1594955468","20","","Aggregated",7.20,0.00,52,62,74,110,150,170,220,260,260,260,260,260,455,1,45,85,8,988,33127
 | 
				
			||||||
 | 
					"1594955470","20","","Aggregated",7.10,0.00,47,62,73,93,150,200,220,260,260,260,260,260,472,1,45,83,8,988,32985
 | 
				
			||||||
 | 
					"1594955472","20","","Aggregated",7.10,0.00,41,60,70,73,110,170,220,270,270,270,270,270,484,1,45,84,8,988,33133
 | 
				
			||||||
 | 
					"1594955474","20","","Aggregated",7.60,0.00,39,56,73,78,110,170,220,270,270,270,270,270,498,1,45,82,8,988,32962
 | 
				
			||||||
 | 
					"1594955476","20","","Aggregated",6.80,0.00,41,56,72,77,99,150,220,270,270,270,270,270,512,1,45,81,8,988,32885
 | 
				
			||||||
 | 
					"1594955478","20","","Aggregated",7.10,0.00,43,73,85,92,110,200,240,270,270,270,270,270,525,1,45,82,8,988,32823
 | 
				
			||||||
 | 
					"1594955480","20","","Aggregated",6.90,0.00,50,76,92,97,110,190,240,290,290,290,290,290,539,1,46,82,8,988,32767
 | 
				
			||||||
 | 
					"1594955482","20","","Aggregated",6.70,0.00,58,85,110,110,150,200,280,290,290,290,290,290,553,1,47,83,8,988,32674
 | 
				
			||||||
 | 
					"1594955484","20","","Aggregated",6.80,0.00,66,90,110,110,180,240,280,290,290,290,290,290,565,1,46,82,8,988,32603
 | 
				
			||||||
 | 
					"1594955486","20","","Aggregated",6.60,0.00,70,87,110,110,150,260,290,500,500,500,500,500,578,1,47,82,8,988,32592
 | 
				
			||||||
 | 
					"1594955488","20","","Aggregated",6.50,0.00,65,81,110,130,230,410,480,500,500,500,500,500,591,1,48,84,8,988,32680
 | 
				
			||||||
 | 
					"1594955490","20","","Aggregated",6.50,0.00,70,89,120,150,260,410,480,500,500,500,500,500,600,1,48,84,8,988,32721
 | 
				
			||||||
 | 
					"1594955492","20","","Aggregated",6.10,0.00,60,79,110,160,230,410,480,500,500,500,500,500,613,2,48,84,8,988,32745
 | 
				
			||||||
 | 
					"1594955494","20","","Aggregated",5.80,0.00,60,79,110,160,230,410,480,500,500,500,500,500,625,2,48,83,8,988,32634
 | 
				
			||||||
 | 
					"1594955496","20","","Aggregated",6.10,0.10,54,73,100,150,190,280,410,480,480,480,480,480,636,2,47,83,8,988,32677
 | 
				
			||||||
 | 
					"1594955498","20","","Aggregated",6.00,0.10,49,65,73,86,170,240,280,390,390,390,390,390,649,2,47,83,8,988,32666
 | 
				
			||||||
 | 
					"1594955500","20","","Aggregated",6.00,0.10,49,58,72,73,150,170,240,390,390,390,390,390,660,2,48,82,8,988,32557
 | 
				
			||||||
 | 
					"1594955502","20","","Aggregated",5.90,0.10,47,54,58,65,73,150,240,390,390,390,390,390,679,2,47,81,8,988,32488
 | 
				
			||||||
 | 
					"1594955504","20","","Aggregated",6.60,0.10,42,51,55,58,73,130,150,390,390,390,390,390,691,2,47,80,8,988,32380
 | 
				
			||||||
 | 
					"1594955506","20","","Aggregated",6.50,0.00,45,53,58,71,130,160,190,220,220,220,220,220,708,2,47,81,8,988,32447
 | 
				
			||||||
 | 
					"1594955508","20","","Aggregated",7.00,0.00,45,54,76,87,140,170,190,220,220,220,220,220,719,2,47,81,8,988,32424
 | 
				
			||||||
 | 
					"1594955510","20","","Aggregated",6.70,0.00,45,53,70,84,140,170,190,220,220,220,220,220,733,2,47,80,8,988,32351
 | 
				
			||||||
 | 
					"1594955512","20","","Aggregated",7.10,0.00,43,53,78,90,150,170,190,220,220,220,220,220,745,2,46,79,8,988,32376
 | 
				
			||||||
 | 
					"1594955514","20","","Aggregated",6.70,0.00,40,58,70,87,150,170,190,220,220,220,220,220,761,2,46,78,8,988,32333
 | 
				
			||||||
 | 
					"1594955516","20","","Aggregated",6.80,0.00,34,43,50,53,69,90,170,170,170,170,170,170,773,2,45,78,8,988,32295
 | 
				
			||||||
 | 
					"1594955518","20","","Aggregated",6.40,0.00,34,43,55,62,89,100,170,220,220,220,220,220,787,3,46,78,8,988,32419
 | 
				
			||||||
 | 
					"1594955519","0","","Aggregated",6.40,0.00,35,43,55,64,89,100,170,220,220,220,220,220,794,3,45,77,8,988,32404
 | 
				
			||||||
		
		
			
  | 
							
								
								
									
										9
									
								
								loadtesting/locust.conf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								loadtesting/locust.conf
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					locustfile = locustfile.py
 | 
				
			||||||
 | 
					expect-workers = 50
 | 
				
			||||||
 | 
					host = http://127.0.0.1:8000
 | 
				
			||||||
 | 
					users = 20
 | 
				
			||||||
 | 
					hatch-rate = 2
 | 
				
			||||||
 | 
					run-time = 2m
 | 
				
			||||||
 | 
					headless = true
 | 
				
			||||||
 | 
					csv=calibre
 | 
				
			||||||
 | 
					only-summary=true
 | 
				
			||||||
							
								
								
									
										184
									
								
								loadtesting/locustfile.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										184
									
								
								loadtesting/locustfile.py
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,184 @@
 | 
				
			|||||||
 | 
					from locust import HttpUser, task, between
 | 
				
			||||||
 | 
					import random
 | 
				
			||||||
 | 
					from sqlalchemy import create_engine
 | 
				
			||||||
 | 
					from sqlalchemy.ext.declarative import declarative_base
 | 
				
			||||||
 | 
					from sqlalchemy.orm import sessionmaker
 | 
				
			||||||
 | 
					import json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# -------------------------------- fetching data to test with
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					with open("./../CalibreWebCompanion/settings.json", "r") as jfile:
 | 
				
			||||||
 | 
					    calpath = json.load(jfile)["CALIBRE_DIR"] + "\\metadata.db"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					engine = create_engine(f'sqlite:///{calpath}')
 | 
				
			||||||
 | 
					Base = declarative_base(engine)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Author(Base):  # needed
 | 
				
			||||||
 | 
					    """"""
 | 
				
			||||||
 | 
					    __tablename__ = 'authors'
 | 
				
			||||||
 | 
					    __table_args__ = {'autoload': True}
 | 
				
			||||||
 | 
					    # has int id, text name, sort
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Identifier(Base):  # needed
 | 
				
			||||||
 | 
					    """"""
 | 
				
			||||||
 | 
					    __tablename__ = 'identifiers'
 | 
				
			||||||
 | 
					    __table_args__ = {'autoload': True}
 | 
				
			||||||
 | 
					    # has int id, int book, text value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Publisher(Base):  # needed
 | 
				
			||||||
 | 
					    """"""
 | 
				
			||||||
 | 
					    __tablename__ = 'publishers'
 | 
				
			||||||
 | 
					    __table_args__ = {'autoload': True}
 | 
				
			||||||
 | 
					    # has int id, text name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Rating(Base):  # needed
 | 
				
			||||||
 | 
					    """"""
 | 
				
			||||||
 | 
					    __tablename__ = 'ratings'
 | 
				
			||||||
 | 
					    __table_args__ = {'autoload': True}
 | 
				
			||||||
 | 
					    # has int id,  int rating
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Series(Base):  # needed
 | 
				
			||||||
 | 
					    """"""
 | 
				
			||||||
 | 
					    __tablename__ = 'series'
 | 
				
			||||||
 | 
					    __table_args__ = {'autoload': True}
 | 
				
			||||||
 | 
					    # has int id,  text name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Tag(Base):  # needed
 | 
				
			||||||
 | 
					    """"""
 | 
				
			||||||
 | 
					    __tablename__ = 'tags'
 | 
				
			||||||
 | 
					    __table_args__ = {'autoload': True}
 | 
				
			||||||
 | 
					    # has int id,  text name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class Book(Base):  # needed
 | 
				
			||||||
 | 
					    """"""
 | 
				
			||||||
 | 
					    __tablename__ = 'books'
 | 
				
			||||||
 | 
					    __table_args__ = {'autoload': True}
 | 
				
			||||||
 | 
					    # has int id,  text title, text sort, time timestamp, time pubdate,
 | 
				
			||||||
 | 
					    # float series_index, text path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def loadSession():
 | 
				
			||||||
 | 
					    """"""
 | 
				
			||||||
 | 
					    metadata = Base.metadata
 | 
				
			||||||
 | 
					    Session = sessionmaker(bind=engine)
 | 
				
			||||||
 | 
					    session = Session()
 | 
				
			||||||
 | 
					    return session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					session = loadSession()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					titles = [i.title for i in session.query(Book).all()]
 | 
				
			||||||
 | 
					authors = [i.name for i in session.query(Author).all()]
 | 
				
			||||||
 | 
					identifiers = [i.val for i in session.query(Identifier).all()]
 | 
				
			||||||
 | 
					book_ids = [i.id for i in session.query(Book).all()]
 | 
				
			||||||
 | 
					author_ids = [i.id for i in session.query(Author).all()]
 | 
				
			||||||
 | 
					publisher_ids = [i.id for i in session.query(Publisher).all()]
 | 
				
			||||||
 | 
					rating_ids = [i.id for i in session.query(Rating).all()]
 | 
				
			||||||
 | 
					series_ids = [i.id for i in session.query(Series).all()]
 | 
				
			||||||
 | 
					tag_ids = [i.id for i in session.query(Tag).all()]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def randlist(mylist):
 | 
				
			||||||
 | 
					    return mylist[random.randint(0, len(mylist) - 1)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserBehavior(HttpUser):
 | 
				
			||||||
 | 
					    wait_time = between(1, 5)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def on_start(self):
 | 
				
			||||||
 | 
					        """ on_start is called when a Locust start before any task is scheduled """
 | 
				
			||||||
 | 
					        r = self.client.get('/accounts/login/')
 | 
				
			||||||
 | 
					        self.client.headers['Referer'] = self.client.base_url
 | 
				
			||||||
 | 
					        n = random.randint(0, 5)
 | 
				
			||||||
 | 
					        self.client.post('/accounts/login/',
 | 
				
			||||||
 | 
					                         {
 | 
				
			||||||
 | 
					                             "username": f"performance{n}",
 | 
				
			||||||
 | 
					                             "password": "profiling1234",
 | 
				
			||||||
 | 
					                             'csrfmiddlewaretoken': r.cookies["csrftoken"]
 | 
				
			||||||
 | 
					                         })
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(10)
 | 
				
			||||||
 | 
					    def search_by_title(self):
 | 
				
			||||||
 | 
					        title = randlist(titles)
 | 
				
			||||||
 | 
					        self.client.get(f"/results/?title={title}", name="search_by_title")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(10)
 | 
				
			||||||
 | 
					    def booklist(self):
 | 
				
			||||||
 | 
					        self.client.get("/books/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(15)
 | 
				
			||||||
 | 
					    def bookdetail(self):
 | 
				
			||||||
 | 
					        pk = randlist(book_ids)
 | 
				
			||||||
 | 
					        self.client.get(f"/book/{pk}", name="/book/<id>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(10)
 | 
				
			||||||
 | 
					    def search_by_author(self):
 | 
				
			||||||
 | 
					        author = randlist(authors)
 | 
				
			||||||
 | 
					        self.client.get(f"/results/?author={author}", name="search_by_author")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(6)
 | 
				
			||||||
 | 
					    def authorlist(self):
 | 
				
			||||||
 | 
					        self.client.get("/authors/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(5)
 | 
				
			||||||
 | 
					    def authordetail(self):
 | 
				
			||||||
 | 
					        pk = randlist(author_ids)
 | 
				
			||||||
 | 
					        self.client.get(f"/author/{pk}", name="/author/<id>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(10)
 | 
				
			||||||
 | 
					    def search_by_id(self):
 | 
				
			||||||
 | 
					        id_ = randlist(identifiers)
 | 
				
			||||||
 | 
					        self.client.get(f"/results/?identifier={id_}", name="search_by_identifier")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(20)
 | 
				
			||||||
 | 
					    def search_generic(self):
 | 
				
			||||||
 | 
					        t = random.randint(0, 3)
 | 
				
			||||||
 | 
					        if not t:
 | 
				
			||||||
 | 
					            term = randlist(titles)
 | 
				
			||||||
 | 
					        elif t == 1:
 | 
				
			||||||
 | 
					            term = randlist(authors)
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            term = randlist(identifiers)
 | 
				
			||||||
 | 
					        self.client.get(f"/results/?generic={term}", name="search_generic")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(8)
 | 
				
			||||||
 | 
					    def searchbad(self):
 | 
				
			||||||
 | 
					        self.client.get("/search/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(1)
 | 
				
			||||||
 | 
					    def ratingslist(self):
 | 
				
			||||||
 | 
					        self.client.get("/ratings/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(10)
 | 
				
			||||||
 | 
					    def ratingdetail(self):
 | 
				
			||||||
 | 
					        pk = randlist(rating_ids)
 | 
				
			||||||
 | 
					        self.client.get(f"/rating/{pk}", name="/rating/<id>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(5)
 | 
				
			||||||
 | 
					    def taglist(self):
 | 
				
			||||||
 | 
					        self.client.get("/tags/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(10)
 | 
				
			||||||
 | 
					    def tagdetail(self):
 | 
				
			||||||
 | 
					        pk = randlist(tag_ids)
 | 
				
			||||||
 | 
					        self.client.get(f"/tag/{pk}", name="/tag/<id>")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(4)
 | 
				
			||||||
 | 
					    def serieslist(self):
 | 
				
			||||||
 | 
					        self.client.get("/series/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(4)
 | 
				
			||||||
 | 
					    def publisherlist(self):
 | 
				
			||||||
 | 
					        self.client.get("/publishers/")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @task(4)
 | 
				
			||||||
 | 
					    def publisherdetail(self):
 | 
				
			||||||
 | 
					        pk = randlist(publisher_ids)
 | 
				
			||||||
 | 
					        self.client.get(f"/publisher/{pk}", name="/publisher/<id>")
 | 
				
			||||||
@@ -3,3 +3,4 @@ django>=3.0.8
 | 
				
			|||||||
django-debug-toolbar>=2.2
 | 
					django-debug-toolbar>=2.2
 | 
				
			||||||
django-silk>=4.0
 | 
					django-silk>=4.0
 | 
				
			||||||
locust>=1.1
 | 
					locust>=1.1
 | 
				
			||||||
 | 
					sqlalchemy>=1.3.15
 | 
				
			||||||
		Reference in New Issue
	
	Block a user