WIP: Deployment #3
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,6 +1,7 @@
|
||||
# project specific
|
||||
settings.json
|
||||
db.sqlite3
|
||||
*.prof
|
||||
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
|
@ -80,6 +80,12 @@ DEBUG_TOOLBAR_PANELS = [
|
||||
########################################################################
|
||||
## 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'
|
||||
|
||||
# Application definition
|
||||
@ -92,14 +98,14 @@ INSTALLED_APPS = [
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
"library",
|
||||
# "silk",
|
||||
# "silk", # DEBUG/profilling purposes
|
||||
# 'debug_toolbar', # DEBUG purposes
|
||||
]
|
||||
|
||||
MIDDLEWARE = [
|
||||
# 'silk.middleware.SilkyMiddleware', # DEBUG/profiling purposes
|
||||
# 'debug_toolbar.middleware.DebugToolbarMiddleware', # DEBUG purposes
|
||||
'django.middleware.cache.UpdateCacheMiddleware', # cache
|
||||
# 'django.middleware.cache.UpdateCacheMiddleware', # cache
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.common.CommonMiddleware',
|
||||
@ -107,8 +113,11 @@ MIDDLEWARE = [
|
||||
'django.contrib.auth.middleware.AuthenticationMiddleware',
|
||||
'django.contrib.messages.middleware.MessageMiddleware',
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'django.middleware.cache.FetchFromCacheMiddleware', # cache
|
||||
# 'django.middleware.cache.FetchFromCacheMiddleware', # cache
|
||||
]
|
||||
## ##
|
||||
########################################################################
|
||||
|
||||
|
||||
ROOT_URLCONF = 'CalibreWebCompanion.urls'
|
||||
|
||||
|
@ -22,6 +22,7 @@ from django.conf import settings
|
||||
from django.urls import include, path
|
||||
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('accounts/', include('django.contrib.auth.urls')),
|
||||
@ -31,7 +32,7 @@ urlpatterns = [
|
||||
|
||||
|
||||
# if settings.DEBUG: # DEBUG purposes
|
||||
# urlpatterns+= [path('silk/', include('silk.urls', namespace='silk'))]
|
||||
# urlpatterns+= [path('silk/', include('silk.urls', namespace='silk'))]
|
||||
# import debug_toolbar
|
||||
# urlpatterns = [
|
||||
# path('__debug__/', include(debug_toolbar.urls)),
|
||||
|
@ -10,19 +10,20 @@ urlpatterns = [
|
||||
path('ratings/', views.RatingListView.as_view(), name='ratings'),
|
||||
path('tags/', views.TagListView.as_view(), name='tags'),
|
||||
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('publisher/<int:pk>', views.PublisherDetailView.as_view(), name='publisher-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('publisher/<int:pk>', views.PublisherDetailView.as_view(),
|
||||
name='publisher-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('results/', views.ResultsView.as_view(), name='results'),
|
||||
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
|
||||
|
||||
|
||||
# might be helpful for vary headers later
|
||||
from django.utils.decorators import method_decorator
|
||||
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
@ -31,6 +34,9 @@ def sign_up(request):
|
||||
class SearchView(generic.TemplateView):
|
||||
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.
|
||||
# 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
|
||||
template_name = 'results.html'
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(ResultsView, self).dispatch(*args, **kwargs)
|
||||
|
||||
def get_queryset(self): # new
|
||||
title = self.request.GET.get('title')
|
||||
author = self.request.GET.get('author')
|
||||
@ -52,8 +61,8 @@ class ResultsView(generic.ListView): # no clue if this is secure.
|
||||
books = books.filter(identifier__val=identifier)
|
||||
if generic:
|
||||
books = books.filter(
|
||||
Q(sort__icontains=generic) |
|
||||
Q(author_sort__icontains=generic) |
|
||||
Q(sort__icontains=generic) |
|
||||
Q(author_sort__icontains=generic) |
|
||||
Q(identifier__val=generic)
|
||||
)
|
||||
return books
|
||||
@ -62,10 +71,16 @@ class ResultsView(generic.ListView): # no clue if this is secure.
|
||||
class AuthorListView(generic.ListView):
|
||||
model = Author
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(AuthorListView, self).dispatch(*args, **kwargs)
|
||||
|
||||
|
||||
class BookListView(generic.ListView):
|
||||
model = Book
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(BookListView, self).dispatch(*args, **kwargs)
|
||||
|
||||
def get_queryset(self):
|
||||
# Annotate the books with ratings, tags, etc
|
||||
# books = Book.objects.annotate(
|
||||
@ -76,21 +91,37 @@ class BookListView(generic.ListView):
|
||||
class PublisherListView(generic.ListView):
|
||||
model = Publisher
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(PublisherListView, self).dispatch(*args, **kwargs)
|
||||
|
||||
|
||||
class RatingListView(generic.ListView):
|
||||
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
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(SeriesListView, self).dispatch(*args, **kwargs)
|
||||
|
||||
|
||||
class TagListView(generic.ListView):
|
||||
model = Tag
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(TagListView, self).dispatch(*args, **kwargs)
|
||||
|
||||
|
||||
class AuthorDetailView(generic.DetailView):
|
||||
model = Author
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(AuthorDetailView, self).dispatch(*args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
# Call the base implementation first to get the context
|
||||
context = super(AuthorDetailView, self).get_context_data(**kwargs)
|
||||
@ -104,6 +135,9 @@ class AuthorDetailView(generic.DetailView):
|
||||
class BookDetailView(generic.DetailView):
|
||||
model = Book
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(BookDetailView, self).dispatch(*args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
# Call the base implementation first to get the context
|
||||
context = super(BookDetailView, self).get_context_data(**kwargs)
|
||||
@ -122,6 +156,9 @@ class BookDetailView(generic.DetailView):
|
||||
class PublisherDetailView(generic.DetailView):
|
||||
model = Publisher
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(PublisherDetailView, self).dispatch(*args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
# Call the base implementation first to get the context
|
||||
context = super(PublisherDetailView, self).get_context_data(**kwargs)
|
||||
@ -135,6 +172,9 @@ class PublisherDetailView(generic.DetailView):
|
||||
class RatingDetailView(generic.DetailView):
|
||||
model = Rating
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(RatingDetailView, self).dispatch(*args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
# Call the base implementation first to get the context
|
||||
context = super(RatingDetailView, self).get_context_data(**kwargs)
|
||||
@ -148,6 +188,9 @@ class RatingDetailView(generic.DetailView):
|
||||
class TagDetailView(generic.DetailView):
|
||||
model = Tag
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(TagDetailView, self).dispatch(*args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
# Call the base implementation first to get the context
|
||||
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)
|
||||
return context
|
||||
|
||||
|
||||
class SeriesDetailView(generic.DetailView):
|
||||
model = Series
|
||||
|
||||
def dispatch(self, *args, **kwargs):
|
||||
return super(SeriesDetailView, self).dispatch(*args, **kwargs)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
# Call the base implementation first to get the context
|
||||
context = super(SeriesDetailView, self).get_context_data(**kwargs)
|
||||
@ -167,4 +214,4 @@ class SeriesDetailView(generic.DetailView):
|
||||
books = Book.objects.prefetch_related("tags", "ratings")
|
||||
books = books.filter(series=context["object"].id)
|
||||
context['books'] = sorted(books, key=lambda x: x.title)
|
||||
return context
|
||||
return context
|
||||
|
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
|
||||
GET,/book/<id>,500 Server Error: Internal Server Error for url: /book/<id>,3
|
|
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
|
||||
GET,/ratings/,9,0,84,76.82164510091145,22.31740951538086,146.39925956726074,30031.0,0.07616573369564714,0.0,84,93,120,130,150,150,150,150,150,150,150,150
|
||||
GET,/search/,48,0,25,34.25489366054535,10.997772216796875,106.93764686584473,27502.3125,0.4062172463767847,0.0,25,36,41,43,72,87,110,110,110,110,110,110
|
||||
GET,/series/,19,0,27,31.892036136827972,19.97995376586914,63.96055221557617,28473.894736842107,0.16079432669081062,0.0,27,31,37,39,62,64,64,64,64,64,64,64
|
||||
GET,/tag/<id>,54,0,49,59.33219415170175,24.969100952148438,120.92876434326172,28703.61111111111,0.45699440217388276,0.0,52,70,85,92,110,110,120,120,120,120,120,120
|
||||
GET,/tags/,36,0,48,66.21244218614366,10.992288589477539,373.7668991088867,33423.77777777778,0.30466293478258855,0.0,51,63,71,73,130,180,370,370,370,370,370,370
|
||||
GET,search_by_author,48,0,35,49.331208070119224,8.999109268188477,187.8821849822998,27508.25,0.4062172463767847,0.0,35,41,56,62,120,160,190,190,190,190,190,190
|
||||
GET,search_by_identifier,58,0,37,46.17996051393706,12.995004653930664,165.89641571044922,27873.603448275862,0.49084583937194814,0.0,38,46,55,59,97,100,120,170,170,170,170,170
|
||||
GET,search_by_title,65,0,35,44.79830815241887,10.993003845214844,264.83631134033203,27183.56923076923,0.5500858544685626,0.0,35,41,50,54,61,110,140,260,260,260,260,260
|
||||
GET,search_generic,117,0,40,51.21477852519761,9.992837905883789,282.82952308654785,28374.79487179487,0.9901545380434127,0.0,40,52,58,67,83,130,180,200,280,280,280,280
|
||||
,Aggregated,794,3,45,77.63347637743433,8.999109268188477,988.3866310119629,32404.799748110832,6.71951028381598,0.025388577898549043,45,62,78,93,160,230,460,610,990,990,990,990
|
|
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>")
|
@ -2,4 +2,5 @@ django>=3.0.8
|
||||
# development
|
||||
django-debug-toolbar>=2.2
|
||||
django-silk>=4.0
|
||||
locust>=1.1
|
||||
locust>=1.1
|
||||
sqlalchemy>=1.3.15
|
Loading…
Reference in New Issue
Block a user