├── .gitignore ├── LICENSE ├── README.md ├── locust_testplan.py └── scripts ├── memcache.settings.inc ├── preptest.sh └── runtest.sh /.gitignore: -------------------------------------------------------------------------------- 1 | output 2 | *.pyc 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Tag1 Consulting, Inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 7 | 8 | 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 9 | 10 | 3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Drupal Loadtest 2 | =============== 3 | 4 | Locust load test and support scripts for testing Drupal sites. 5 | 6 | This locust test plan and scripts are used to test out the [Drupal Memcache module](https://drupal.org/project/memcache). 7 | 8 | Assumptions 9 | ----------- 10 | These scripts assume: 11 | 1. A Drupal installation -- webroot and database. 12 | 2. [Locust](http://locust.io/) installed 13 | 14 | Running Tests 15 | ------------- 16 | There are two scripts in the scripts/ directory: `preptest.sh` and `runtest.sh`. 17 | 18 | The `preptest.sh` script only needs to be run once per-VM. The VM should already have a Drupal webroot setup. The script will install the devel and memcache modules (there's a configurable setting for which memcache module version to install), and then use drush devel_generate calls to generate content -- the amount of content is also configurable. 19 | 20 | In addition, `preptest.sh` prepares the site for tests by populating it with content and configuring some settings (memcache module, user logins, etc.). 21 | 22 | Once that is complete, it will create a database dump in /root so that the same database can be reloaded for subsequent tests. 23 | 24 | 25 | The `runtest.sh` script restarts services (mysqld, httpd, memcached) to ensure consistency between tests. Then it runs the locust load test, copies test output data to the webroot, and outputs memcached stats from the test run into a summary report. 26 | 27 | `runtest.sh` requires one argument, a tag which will be appended to the output directory as a test identifier. 28 | -------------------------------------------------------------------------------- /locust_testplan.py: -------------------------------------------------------------------------------- 1 | from locust import HttpLocust, TaskSet, task, events 2 | from bs4 import BeautifulSoup 3 | import random 4 | import string 5 | 6 | def is_static_file(file): 7 | if "/misc" in file: 8 | return True 9 | elif "/themes" in file: 10 | return True 11 | else: 12 | return False 13 | 14 | def random_word(): 15 | """Return 1 to 12 random characters, a-z inclusive.""" 16 | length = random.randint(1, 12) 17 | return "".join( [random.choice(string.letters[:26]) for i in xrange(length)] ) 18 | 19 | def random_sentence(): 20 | """Return 3 to 15 random words, capitalizing the first and ending 21 | with a period to mimic a sentence.""" 22 | length = random.randint(3, 15) 23 | return (" ".join(random_word() for i in xrange(length)) + '.').capitalize() 24 | 25 | def random_paragraph(): 26 | """Return 3 to 15 random sentences, seperating with a space.""" 27 | length = random.randint(3, 15) 28 | return (" ".join(random_sentence() for i in xrange(length))) 29 | 30 | def fetch_static_assets(session, response): 31 | """Determine if a URL in the web page is a static asset and should be 32 | downloaded.""" 33 | resource_urls = set() 34 | soup = BeautifulSoup(response.text, "html.parser") 35 | 36 | for res in soup.find_all(src=True): 37 | url = res['src'] 38 | if is_static_file(url): 39 | resource_urls.add(url) 40 | else: 41 | print "Skipping: " + url 42 | 43 | for url in set(resource_urls): 44 | session.client.get(url, name="(Static File)") 45 | 46 | class AnonBrowsingUser(TaskSet): 47 | @task(15) 48 | def frontpage(l): 49 | """View the front page.""" 50 | response = l.client.get("/", name="(Anonymous) Front page") 51 | fetch_static_assets(l, response) 52 | 53 | @task(10) 54 | def nodepage(l): 55 | """preptest.sh creates nodes from 1 through 10,000: randomly 56 | view one of these nodes. 57 | """ 58 | nid = random.randint(1, 10000) 59 | l.client.get("/node/%i" % nid, name="(Anonymous) /node/[nid]") 60 | 61 | @task(3) 62 | def profilepage(l): 63 | """preptest.sh creates users from 3 through 5,002: randomly 64 | view one of these user profiles. 65 | """ 66 | uid = random.randint(3, 5002) 67 | l.client.get("/user/%i" % uid, name="(Anonymous) /user/[uid]") 68 | 69 | class AuthBrowsingUser(TaskSet): 70 | def on_start(l): 71 | """Log into the website to simulate authenticated traffic.""" 72 | response = l.client.get("/user", name="(Auth) Login") 73 | soup = BeautifulSoup(response.text, "html.parser") 74 | drupal_form_id = soup.select('input[name="form_build_id"]')[0]["value"] 75 | """preptest.sh creates test users starting from uid3 with usernames 76 | like "userUID" and password "12345". Randomly log into one of these 77 | users.""" 78 | username = "user" + str(random.randint(3, 1000)) 79 | password = "12345" 80 | r = l.client.post("/user", {"name":username, "pass":password, "form_id":"user_login", "op":"Log+in", "form_build_id":drupal_form_id}, name="(Auth) Logging in: /user") 81 | 82 | @task(15) 83 | def frontpage(l): 84 | """View the front page.""" 85 | response = l.client.get("/", name="(Auth) Front page") 86 | fetch_static_assets(l, response) 87 | 88 | @task(10) 89 | def nodepage(l): 90 | """preptest.sh creates nodes from 1 through 10,000: randomly 91 | view one of these nodes. 92 | """ 93 | nid = random.randint(1, 10000) 94 | l.client.get("/node/%i" % nid, name="(Auth) /node/[nid]") 95 | 96 | @task(3) 97 | def profilepage(l): 98 | """preptest.sh creates users from 3 through 5,002: randomly 99 | view one of these user profiles. 100 | """ 101 | uid = random.randint(3, 5002) 102 | l.client.get("/user/%i" % uid, name="(Auth) /user/[uid]") 103 | 104 | @task(3) 105 | def postcomments(l): 106 | """preptest.sh creates nodes from 1 through 10,000: randomly 107 | add a comment to one of them, if it is a node type that has 108 | comments enabled. 109 | """ 110 | nid = random.randint(1, 10000) 111 | response = l.client.get("/comment/reply/%i" % nid, name="(Auth) Comment form") 112 | soup = BeautifulSoup(response.text, "html.parser") 113 | drupal_form_build_id_object = soup.select('input[name="form_build_id"]') 114 | drupal_form_token_object = soup.select('input[name="form_token"]') 115 | if drupal_form_build_id_object and drupal_form_token_object: 116 | drupal_form_build_id = drupal_form_build_id_object[0]["value"] 117 | drupal_form_token = drupal_form_token_object[0]["value"] 118 | subject = random_sentence() 119 | response = l.client.post("/comment/reply/%i" % nid, {"subject":subject, "comment":random_paragraph(), "form_id":"comment_form", "form_token":drupal_form_token, "op":"Save", "form_build_id":drupal_form_build_id}, name="(Auth) Posting comment", catch_response=True) 120 | if response.status_code != 200: 121 | response.failure("Failed to post comment: " + str(response.status_code)) 122 | elif subject not in response.content: 123 | response.failure("Failed to post comment: comment not showing up") 124 | else: 125 | response.success() 126 | 127 | class WebsiteAuthUser(HttpLocust): 128 | weight = 1 129 | task_set = AuthBrowsingUser 130 | 131 | class WebsiteAnonUser(HttpLocust): 132 | weight = 4 133 | task_set = AnonBrowsingUser 134 | -------------------------------------------------------------------------------- /scripts/memcache.settings.inc: -------------------------------------------------------------------------------- 1 | 2 | // Drupal 6 memcached settings. 3 | $conf['cache_inc'] ='sites/all/modules/memcache/memcache.inc'; 4 | $conf['lock_inc'] = 'sites/all/modules/memcache/memcache-lock.inc'; 5 | $conf['memcache_stampede_protection'] = TRUE; 6 | // The 'cache_form' bin must be assigned to non-volatile storage. 7 | $conf['memcache_bins']['cache_form'] = 'database'; 8 | -------------------------------------------------------------------------------- /scripts/preptest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # Prep a base Drupal install for memcache testing. 4 | # This assumes that $WEBDIR contains a working Drupal install. 5 | 6 | WEBDIR=/var/www/html 7 | MEMCACHE_SETTINGS_FILE=memcache.settings.inc 8 | MEMCACHE_VERSION=6.x-1.11 9 | DATABASE_NAME=drupal6loadtest 10 | 11 | USER_COUNT=5000 12 | CONTENT_COUNT=10000 13 | MAX_COMMENTS=20 14 | 15 | # Get the full directory for the memcache settings file (same dir as this script). 16 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" 17 | MEMCACHE_SETTINGS_FILE=${DIR}/${MEMCACHE_SETTINGS_FILE} 18 | 19 | # Create modules directory if it doesn't already exist. 20 | mkdir -p ${WEBDIR}/sites/all/modules 21 | 22 | # Install devel module and enable devel_generate. 23 | drush dl devel --destination=${WEBDIR}/sites/all/modules 24 | drush -r ${WEBDIR} -y en devel_generate 25 | 26 | # Create content. 27 | echo "Creating ${USER_COUNT} users, this may take a while..." 28 | drush -r ${WEBDIR} generate-users ${USER_COUNT} 29 | echo "Creating ${CONTENT_COUNT} nodes with up to ${MAX_COMMENTS} comments each, this may take a while..." 30 | drush -r ${WEBDIR} generate-content ${CONTENT_COUNT} ${MAX_COMMENTS} 31 | 32 | # Install memcache module 33 | drush dl memcache-${MEMCACHE_VERSION} --destination=${WEBDIR}/sites/all/modules 34 | 35 | # Add memcache configuration to settings.php 36 | cat ${MEMCACHE_SETTINGS_FILE} >> ${WEBDIR}/sites/default/settings.php 37 | 38 | # Update user names and passwords (sets passwords to 'supersecrettestuser'). 39 | # The CSV data for the test expects these specific usernames (e.g. 'user1', 'user2' from 1-5000). 40 | echo "Setting Drupal usernames and passwords to those that the test expects..." 41 | for i in $(seq 2 5001) 42 | do 43 | mysql -e "UPDATE ${DATABASE_NAME}.users SET name='user${i}', pass=MD5('12345') WHERE uid = ${i};" 44 | done 45 | 46 | echo "Updating permissions: allow anonymous to access user profiles." 47 | # Update permissions -- the test attempts to view user profiles as an anoymous user, need to allow that. 48 | drush -r ${WEBDIR} role-add-perm 'anonymous user' 'access user profiles' 49 | 50 | echo "Creating a mysqldump of the drupal install with test data..." 51 | mysqldump --single-transaction ${DATABASE_NAME} | gzip > /root/drupal_with_test_content.sql.gz 52 | ls -lh /root/drupal_with_test_content.sql.gz 53 | 54 | echo "All done with test prep -- run tests using the runtest.sh script." 55 | 56 | echo "@TODO (should be scripted):" 57 | echo " - enable posting comments w/o preview on both content types" 58 | echo " - add 'access user profiles' to 'authenticated user'" 59 | echo " - enable normal page cache" 60 | -------------------------------------------------------------------------------- /scripts/runtest.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Pass the script a tag to identify this testrun (e.g. memcache module version being tested) 4 | TAG=$1 5 | 6 | if [ "$TAG" == "" ] 7 | then 8 | echo "You must pass a tag to the script -- will be appeneded to the output directory for this test." 9 | exit 1 10 | fi 11 | 12 | DOMAIN="http://loadtest.dev" 13 | 14 | LOCUST=/usr/local/bin/locust 15 | LOCUST_PLAN=/root/drupal-loadtest/locust_testplan.py 16 | 17 | RESTART_MYSQL="/usr/local/etc/rc.d/mysql-server restart" 18 | RESTART_APACHE="service apache24 restart" 19 | RESTART_MEMCACHED="service memcached restart" 20 | 21 | USERS=100 22 | RAMPUP=10 23 | REQUESTS=50000 24 | 25 | DATE=`date +%d-%m-%y--%H:%M:%S-$TAG` 26 | WEBROOT="/var/www/html" 27 | OUTPUT="$WEBROOT/$DATE" 28 | 29 | mkdir $OUTPUT 30 | 31 | NC="/usr/bin/nc -N" 32 | 33 | IPADDR="ConfigureMe" 34 | 35 | # This is output by preptest.sh... 36 | SQL_DUMP=/root/drupal_with_test_content.sql.gz 37 | DB_NAME=drupal6loadtest 38 | 39 | # Load the database into MySQL so each test starts with the same base data. 40 | echo "Reloading DB, this will likely take a few minutes..." 41 | mysql -e "DROP DATABASE $DB_NAME" 42 | mysql -e "CREATE DATABASE $DB_NAME" 43 | gunzip -c $SQL_DUMP | mysql $DB_NAME 44 | 45 | $RESTART_MYSQL 2>&1 > $OUTPUT/mysql_restart.log 46 | $RESTART_APACHE 2>&1 > $OUTPUT/apache_restart.log 47 | $RESTART_MEMCACHED 2>&1 > $OUTPUT/memcached_restart.log 48 | 49 | # Run loadtest 50 | echo $LOCUST -f $LOCUST_PLAN --host=$DOMAIN --no-web -c $USERS -r $RAMPUP -n $REQUESTS --only-summary --logfile=$OUTPUT/locust.log 51 | $LOCUST -f $LOCUST_PLAN --host=$DOMAIN --no-web -c $USERS -r $RAMPUP -n $REQUESTS --only-summary --logfile=$OUTPUT/locust.log > $OUTPUT/locust.txt 2>&1 52 | 53 | rm -f "$WEBROOT/latest" 54 | ln -s $OUTPUT "$WEBROOT/latest" 55 | 56 | # Add .htaccess to override Drupal's default of disabling indexes. 57 | echo "Options +Indexes" > $WEBROOT/latest/.htaccess 58 | echo 'stats' | $NC localhost 11211 > "$WEBROOT/latest/memcached.stats.txt" 59 | 60 | SUMMARY="$WEBROOT/latest/summary.tsv" 61 | 62 | grep "STAT total_connections" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' > $SUMMARY 2>&1 63 | grep "STAT cmd_get" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 64 | grep "STAT cmd_set" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 65 | grep "STAT get_hits" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 66 | grep "STAT get_misses" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 67 | grep "STAT delete_hits" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 68 | grep "STAT delete_misses" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 69 | grep "STAT incr_hits" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 70 | grep "STAT bytes_read" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 71 | grep "STAT bytes_written" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 72 | grep "STAT evictions" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 73 | grep "STAT total_items" "$WEBROOT/latest/memcached.stats.txt" | awk '{print "\"" $2 "\" " $3}' >> $SUMMARY 2>&1 74 | 75 | echo >> $SUMMARY 2>&1 76 | 77 | GETS=`grep "STAT cmd_get" "$WEBROOT/latest/memcached.stats.txt" | awk '{print $3}' | tr -d '\r\n\f'` >> $SUMMARY 2>&1 78 | HITS=`grep "STAT get_hits" "$WEBROOT/latest/memcached.stats.txt" | awk '{print $3}' | tr -d '\r\n\f'` >> $SUMMARY 2>&1 79 | MISSES=`grep "STAT get_misses" "$WEBROOT/latest/memcached.stats.txt" | awk '{print $3}' | tr -d '\r\n\f'` >> $SUMMARY 2>&1 80 | RATE=`echo "scale=4;$HITS / $GETS * 100" | bc` >> $SUMMARY 2>&1 81 | echo "\"Hit rate\" $RATE%" >> $SUMMARY 2>&1 82 | RATE=`echo "scale=4;$MISSES / $GETS * 100" | bc` >> $SUMMARY 2>&1 83 | echo "\"Miss rate\" $RATE%" >> $SUMMARY 2>&1 84 | 85 | echo >> $SUMMARY 2>&1 86 | 87 | echo "Type Total Err ms (Average) ms (Max) Rate" >> $SUMMARY 2>&1 88 | 89 | ANON_GET_FRONTPAGE=`grep Anonymous $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $5}'` 90 | ANON_GET_FRONTPAGE_ERR=`grep Anonymous $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $6}'` 91 | ANON_GET_FRONTPAGE_AVG=`grep Anonymous $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $7}'` 92 | ANON_GET_FRONTPAGE_MAX=`grep Anonymous $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $9}'` 93 | ANON_GET_FRONTPAGE_REQ=`grep Anonymous $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $12}'` 94 | echo "\"Anon frontpage\" $ANON_GET_FRONTPAGE $ANON_GET_FRONTPAGE_ERR $ANON_GET_FRONTPAGE_AVG $ANON_GET_FRONTPAGE_MAX $ANON_GET_FRONTPAGE_REQ" >> $SUMMARY 2>&1 95 | 96 | ANON_GET_NODE=`grep Anonymous $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $4}'` 97 | ANON_GET_NODE_ERR=`grep Anonymous $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $5}'` 98 | ANON_GET_NODE_AVG=`grep Anonymous $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $6}'` 99 | ANON_GET_NODE_MAX=`grep Anonymous $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $8}'` 100 | ANON_GET_NODE_REQ=`grep Anonymous $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $11}'` 101 | echo "\"Anon node\" $ANON_GET_NODE $ANON_GET_NODE_ERR $ANON_GET_NODE_AVG $ANON_GET_NODE_MAX $ANON_GET_NODE_REQ" >> $SUMMARY 2>&1 102 | 103 | ANON_GET_PROFILE=`grep Anonymous $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $4}'` 104 | ANON_GET_PROFILE_ERR=`grep Anonymous $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $5}'` 105 | ANON_GET_PROFILE_AVG=`grep Anonymous $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $6}'` 106 | ANON_GET_PROFILE_MAX=`grep Anonymous $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $8}'` 107 | ANON_GET_PROFILE_REQ=`grep Anonymous $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $11}'` 108 | echo "\"Anon profile\" $ANON_GET_PROFILE $ANON_GET_PROFILE_ERR $ANON_GET_PROFILE_AVG $ANON_GET_PROFILE_MAX $ANON_GET_PROFILE_REQ" >> $SUMMARY 2>&1 109 | 110 | AUTH_GET_LOGIN=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $5}'` 111 | AUTH_GET_LOGIN_ERR=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $6}'` 112 | AUTH_GET_LOGIN_AVG=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $7}'` 113 | AUTH_GET_LOGIN_MAX=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $9}'` 114 | AUTH_GET_LOGIN_REQ=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $12}'` 115 | echo "\"Anon load login form\" $AUTH_GET_LOGIN $AUTH_GET_LOGIN_ERR $AUTH_GET_LOGIN_AVG $AUTH_GET_LOGIN_MAX $AUTH_GET_LOGIN_REQ" >> $SUMMARY 2>&1 116 | 117 | AUTH_POST_LOGIN=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $5}'` 118 | AUTH_POST_LOGIN_ERR=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $6}'` 119 | AUTH_POST_LOGIN_AVG=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $7}'` 120 | AUTH_POST_LOGIN_MAX=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $9}'` 121 | AUTH_POST_LOGIN_REQ=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $12}'` 122 | echo "\"Auth post login\" $AUTH_POST_LOGIN $AUTH_POST_LOGIN_ERR $AUTH_POST_LOGIN_AVG $AUTH_POST_LOGIN_MAX $AUTH_POST_LOGIN_REQ" >> $SUMMARY 2>&1 123 | 124 | AUTH_GET_NODE=`grep Auth $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $4}'` 125 | AUTH_GET_NODE_ERR=`grep Auth $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $5}'` 126 | AUTH_GET_NODE_AVG=`grep Auth $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $6}'` 127 | AUTH_GET_NODE_MAX=`grep Auth $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $8}'` 128 | AUTH_GET_NODE_REQ=`grep Auth $OUTPUT/locust.txt | grep nid | head -1 | awk '{print $11}'` 129 | echo "\"Auth node\" $AUTH_GET_NODE $AUTH_GET_NODE_ERR $AUTH_GET_NODE_AVG $AUTH_GET_NODE_MAX $AUTH_GET_NODE_REQ" >> $SUMMARY 2>&1 130 | 131 | AUTH_GET_PROFILE=`grep Auth $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $4}'` 132 | AUTH_GET_PROFILE_ERR=`grep Auth $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $5}'` 133 | AUTH_GET_PROFILE_AVG=`grep Auth $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $6}'` 134 | AUTH_GET_PROFILE_MAX=`grep Auth $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $8}'` 135 | AUTH_GET_PROFILE_REQ=`grep Auth $OUTPUT/locust.txt | grep uid | head -1 | awk '{print $11}'` 136 | echo "\"Auth profile\" $AUTH_GET_PROFILE $AUTH_GET_PROFILE_ERR $AUTH_GET_PROFILE_AVG $AUTH_GET_PROFILE_MAX $AUTH_GET_PROFILE_REQ" >> $SUMMARY 2>&1 137 | 138 | AUTH_GET_FRONTPAGE=`grep Auth $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $5}'` 139 | AUTH_GET_FRONTPAGE_ERR=`grep Auth $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $6}'` 140 | AUTH_GET_FRONTPAGE_AVG=`grep Auth $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $7}'` 141 | AUTH_GET_FRONTPAGE_MAX=`grep Auth $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $9}'` 142 | AUTH_GET_FRONTPAGE_REQ=`grep Auth $OUTPUT/locust.txt | grep Front | head -1 | awk '{print $12}'` 143 | echo "\"Auth frontpage\" $AUTH_GET_FRONTPAGE $AUTH_GET_FRONTPAGE_ERR $AUTH_GET_FRONTPAGE_AVG $AUTH_GET_FRONTPAGE_MAX $AUTH_GET_FRONTPAGE_REQ" >> $SUMMARY 2>&1 144 | 145 | AUTH_GET_COMMENT=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $5}'` 146 | AUTH_GET_COMMENT_ERR=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $6}'` 147 | AUTH_GET_COMMENT_AVG=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $7}'` 148 | AUTH_GET_COMMENT_MAX=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $9}'` 149 | AUTH_GET_COMMENT_REQ=`grep Auth $OUTPUT/locust.txt | grep Comment | head -1 | awk '{print $12}'` 150 | echo "\"Auth comment form\" $AUTH_GET_COMMENT $AUTH_GET_COMMENT_ERR $AUTH_GET_COMMENT_AVG $AUTH_GET_COMMENT_MAX $AUTH_GET_COMMENT_REQ" >> $SUMMARY 2>&1 151 | 152 | AUTH_POST_COMMENT=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $5}'` 153 | AUTH_POST_COMMENT_ERR=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $6}'` 154 | AUTH_POST_COMMENT_AVG=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $7}'` 155 | AUTH_POST_COMMENT_MAX=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $9}'` 156 | AUTH_POST_COMMENT_REQ=`grep Auth $OUTPUT/locust.txt | grep Posting | head -1 | awk '{print $12}'` 157 | echo "\"Auth post comment\" $AUTH_POST_COMMENT $AUTH_POST_COMMENT_ERR $AUTH_POST_COMMENT_AVG $AUTH_POST_COMMENT_MAX $AUTH_POST_COMMENT_REQ" >> $SUMMARY 2>&1 158 | 159 | STATIC_FILE=`grep GET $OUTPUT/locust.txt | grep Static | head -1 | awk '{print $4}'` 160 | STATIC_FILE_ERR=`grep GET $OUTPUT/locust.txt | grep Static | head -1 | awk '{print $5}'` 161 | STATIC_FILE_AVG=`grep GET $OUTPUT/locust.txt | grep Static | head -1 | awk '{print $6}'` 162 | STATIC_FILE_MAX=`grep GET $OUTPUT/locust.txt | grep Static | head -1 | awk '{print $8}'` 163 | STATIC_FILE_REQ=`grep GET $OUTPUT/locust.txt | grep Static | head -1 | awk '{print $11}'` 164 | echo "\"Static file\" $STATIC_FILE $STATIC_FILE_ERR $STATIC_FILE_AVG $STATIC_FILE_MAX $STATIC_FILE_REQ" >> $SUMMARY 2>&1 165 | 166 | TOTAL=`grep Total $OUTPUT/locust.txt | head -1 | awk '{print $2}'` 167 | TOTAL_ERR=`grep Total $OUTPUT/locust.txt | head -1 | awk '{print $3}'` 168 | TOTAL_AVG=`grep Total $OUTPUT/locust.txt | head -1 | awk '{print $99}'` 169 | TOTAL_MAX=`grep Total $OUTPUT/locust.txt | head -1 | awk '{print $99}'` 170 | TOTAL_REQ=`grep Total $OUTPUT/locust.txt | head -1 | awk '{print $4}'` 171 | echo "\"Total\" $TOTAL $TOTAL_ERR $TOTAL_AVG $TOTAL_MAX $TOTAL_REQ" >> $SUMMARY 2>&1 172 | 173 | echo >> $SUMMARY 2>&1 174 | 175 | cat $SUMMARY 176 | 177 | echo "Complete results can be found in $WEBROOT/latest." 178 | echo "Or at http://$IPADDR/$DATE" 179 | echo "TSV-formatted summary at http://$IPADDR/$DATE/summary.tsv" 180 | --------------------------------------------------------------------------------