From fa75817a556755dc05ca658ed25450de4f405015 Mon Sep 17 00:00:00 2001 From: Charles Wang Date: Wed, 15 Oct 2014 16:07:44 -0400 Subject: [PATCH] add list_tables, fix benchmark_runner --- benchmark_runner.py | 2 +- tests/list_tables/__init__.py | 2 + tests/list_tables/config.py | 20 ++ tests/list_tables/ks_config.py | 20 ++ tests/list_tables/queries.py | 633 +++++++++++++++++++++++++++++++++ tests/list_tables/scenario.py | 71 ++++ tests/list_tables/setup.py | 126 +++++++ tests/list_tables/teardown.py | 41 +++ 8 files changed, 914 insertions(+), 1 deletion(-) create mode 100644 tests/list_tables/__init__.py create mode 100644 tests/list_tables/config.py create mode 100644 tests/list_tables/ks_config.py create mode 100644 tests/list_tables/queries.py create mode 100644 tests/list_tables/scenario.py create mode 100644 tests/list_tables/setup.py create mode 100644 tests/list_tables/teardown.py diff --git a/benchmark_runner.py b/benchmark_runner.py index eb0c567..094e127 100644 --- a/benchmark_runner.py +++ b/benchmark_runner.py @@ -217,7 +217,7 @@ def run_benchmark(config_file, config, testcase): config = template for key in case: config = config.replace('{{%s}}' % key, case[key]) - with open(os.path.join(sys.argv[2], 'config.py', 'w') as f: + with open(os.path.join(sys.argv[2], 'config.py'), 'w') as f: f.write(config) try: run_benchmark(sys.argv[1], conf, sys.argv[2]) diff --git a/tests/list_tables/__init__.py b/tests/list_tables/__init__.py new file mode 100644 index 0000000..f0a5647 --- /dev/null +++ b/tests/list_tables/__init__.py @@ -0,0 +1,2 @@ +from setup import setup +from teardown import cleanup diff --git a/tests/list_tables/config.py b/tests/list_tables/config.py new file mode 100644 index 0000000..e505ad6 --- /dev/null +++ b/tests/list_tables/config.py @@ -0,0 +1,20 @@ +SLAVE_COUNT = 2 +LOCUST_COUNT = 10 +HATCH_RATE = 10 +MIN_WAIT = 0 +MAX_WAIT = 0 +TABLES_CREATED_3_FIELDS_NO_LSI = 10 +TABLES_CREATED_3_FIELDS_1_LSI = 10 +TABLES_CREATED_10_FIELDS_5_LSI = 10 +TABLE_NAME = "item_metadata" +LIMIT = 10 +TOKEN_PROJECT = "/tmp/token_project.txt" +TABLE_LIST='/tmp/table_list.txt' +ITEM_KEY_LIST = '/tmp/item_key_list.txt' +CASSANDRA_NODES='127.0.0.1' +CASSANDRA_CLEANER='/root/scripts/cleaner.sh' + +token_req_headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json' +} diff --git a/tests/list_tables/ks_config.py b/tests/list_tables/ks_config.py new file mode 100644 index 0000000..e9cebb7 --- /dev/null +++ b/tests/list_tables/ks_config.py @@ -0,0 +1,20 @@ +import json +import os.path + +import config as cfg + + +TOKEN = None +PROJECT_ID = None + +if os.path.isfile(cfg.TOKEN_PROJECT): + with open(cfg.TOKEN_PROJECT) as token_proj_file: + token_project = json.load(token_proj_file) + TOKEN = token_project['token'].strip() + PROJECT_ID = token_project['project_id'].strip() + +req_headers = { + 'Content-Type': 'application/json', + 'Accept': 'application/json', + 'X-Auth-Token': TOKEN +} diff --git a/tests/list_tables/queries.py b/tests/list_tables/queries.py new file mode 100644 index 0000000..88714eb --- /dev/null +++ b/tests/list_tables/queries.py @@ -0,0 +1,633 @@ +CREATE_TABLE_3_FIELDS_NO_LSI_RQ = ''' +{ + "table_name": "%s", + "attribute_definitions": [ + { + "attribute_name": "ForumName", + "attribute_type": "S" + }, + { + "attribute_name": "Subject", + "attribute_type": "S" + }, + { + "attribute_name": "LastPostedBy", + "attribute_type": "S" + } + ], + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "Subject", + "key_type": "RANGE" + } + ] +} +''' + +CREATE_TABLE_3_FIELDS_1_LSI_RQ = ''' +{ + "table_name": "%s", + "attribute_definitions": [ + { + "attribute_name": "ForumName", + "attribute_type": "S" + }, + { + "attribute_name": "Subject", + "attribute_type": "S" + }, + { + "attribute_name": "LastPostedBy", + "attribute_type": "S" + } + ], + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "Subject", + "key_type": "RANGE" + } + ], + "local_secondary_indexes": [ + { + "index_name": "LastPostedByIndex", + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "LastPostedBy", + "key_type": "RANGE" + } + ], + "projection": { + "projection_type": "ALL" + } + } + ] +} +''' + +CREATE_TABLE_10_FIELDS_NO_LSI_RQ = ''' +{ + "table_name": "%s", + "attribute_definitions": [ + { + "attribute_name": "ForumName", + "attribute_type": "S" + }, + { + "attribute_name": "Subject", + "attribute_type": "S" + }, + { + "attribute_name": "LastPostedBy", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField1", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField2", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField3", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField4", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField5", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField6", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField7", + "attribute_type": "S" + } + ], + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "Subject", + "key_type": "RANGE" + } + ] +} +''' + +CREATE_TABLE_10_FIELDS_5_LSI_RQ = ''' +{ + "table_name": "%s", + "attribute_definitions": [ + { + "attribute_name": "ForumName", + "attribute_type": "S" + }, + { + "attribute_name": "Subject", + "attribute_type": "S" + }, + { + "attribute_name": "LastPostedBy", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField1", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField2", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField3", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField4", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField5", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField6", + "attribute_type": "S" + }, + { + "attribute_name": "AdditionalField7", + "attribute_type": "S" + } + ], + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "Subject", + "key_type": "RANGE" + } + ], + "local_secondary_indexes": [ + { + "index_name": "LastPostedByIndex", + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "LastPostedBy", + "key_type": "RANGE" + } + ], + "projection": { + "projection_type": "ALL" + } + }, + { + "index_name": "AdditionalField1Index", + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "AdditionalField1", + "key_type": "RANGE" + } + ], + "projection": { + "projection_type": "ALL" + } + }, + { + "index_name": "AdditionalField2Index", + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "AdditionalField2", + "key_type": "RANGE" + } + ], + "projection": { + "projection_type": "ALL" + } + }, + { + "index_name": "AdditionalField3Index", + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "AdditionalField3", + "key_type": "RANGE" + } + ], + "projection": { + "projection_type": "ALL" + } + }, + { + "index_name": "AdditionalField4Index", + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "AdditionalField4", + "key_type": "RANGE" + } + ], + "projection": { + "projection_type": "ALL" + } + } + ] +} +''' + +PUT_ITEM_3_FIELDS_NO_LSI_RQ = ''' +{ + "item": { + "ForumName": {"S": "MagnetoDB"}, + "Subject": {"S": "%s"}, + "LastPostedBy": {"S": "%s"} + } +} +''' + +PUT_ITEM_3_FIELDS_1_LSI_RQ = ''' +{ + "item": { + "ForumName": {"S": "MagnetoDB"}, + "Subject": {"S": "%s"}, + "LastPostedBy": {"S": "%s"} + } +} +''' + +PUT_ITEM_10_FIELDS_5_LSI_RQ = ''' +{ + "item": { + "ForumName": {"S": "MagnetoDB"}, + "Subject": {"S": "%s"}, + "LastPostedBy": {"S": "%s"}, + "AdditionalField1": {"S": "%s"}, + "AdditionalField2": {"S": "%s"}, + "AdditionalField3": {"S": "%s"}, + "AdditionalField4": {"S": "%s"}, + "AdditionalField5": {"S": "%s"}, + "AdditionalField6": {"S": "%s"}, + "AdditionalField7": {"S": "%s"} + } +} +''' + +GET_ITEM_3_FIELDS_NO_LSI_RQ = ''' +{ + "key": { + "ForumName": { + "S": "MagnetoDB" + }, + "Subject": { + "S": "%s" + } + }, + "attributes_to_get": ["LastPostedBy"], + "consistent_read": true +} +''' + +GET_ITEM_3_FIELDS_1_LSI_RQ = ''' +{ + "key": { + "ForumName": { + "S": "MagnetoDB" + }, + "Subject": { + "S": "%s" + } + }, + "attributes_to_get": ["LastPostedBy"], + "consistent_read": true +} +''' + +GET_ITEM_10_FIELDS_5_LSI_RQ = ''' +{ + "key": { + "ForumName": { + "S": "MagnetoDB" + }, + "Subject": { + "S": "%s" + } + }, + "attributes_to_get": ["LastPostedBy", "AdditionalField1", + "AdditionalField2", "AdditionalField3", + "AdditionalField4", "AdditionalField5", + "AdditionalField6", "AdditionalField7"], + "consistent_read": true +} +''' + +QUERY_3_FIELDS_NO_LSI_RQ1 = ''' +{ + "key_conditions": { + "ForumName": { + "attribute_value_list": [ + { + "S": "MagnetoDB" + } + ], + "comparison_operator": "EQ" + } + } +} +''' + +QUERY_3_FIELDS_1_LSI_RQ1 = QUERY_3_FIELDS_NO_LSI_RQ1 + +QUERY_3_FIELDS_1_LSI_RQ2 = ''' +{ + "index_name": "LastPostedByIndex", + "key_conditions": { + "ForumName": { + "attribute_value_list": [ + { + "S": "MagnetoDB" + } + ], + "comparison_operator": "EQ" + }, + "LastPostedBy": { + "attribute_value_list": [ + { + "S": "%s" + } + ], + "comparison_operator": "EQ" + } + } +} +''' + +QUERY_10_FIELDS_5_LSI_RQ1 = QUERY_3_FIELDS_NO_LSI_RQ1 + +QUERY_10_FIELDS_5_LSI_RQ2 = QUERY_3_FIELDS_1_LSI_RQ2 + +QUERY_10_FIELDS_5_LSI_RQ3 = ''' +{ + "index_name": "AdditionalField1Index", + "key_conditions": { + "ForumName": { + "attribute_value_list": [ + { + "S": "MagnetoDB" + } + ], + "comparison_operator": "EQ" + }, + "AdditionalField1": { + "attribute_value_list": [ + { + "S": "%s" + } + ], + "comparison_operator": "EQ" + } + } +} +''' + +QUERY_10_FIELDS_5_LSI_RQ4 = ''' +{ + "index_name": "AdditionalField2Index", + "key_conditions": { + "ForumName": { + "attribute_value_list": [ + { + "S": "MagnetoDB" + } + ], + "comparison_operator": "EQ" + }, + "AdditionalField2": { + "attribute_value_list": [ + { + "S": "%s" + } + ], + "comparison_operator": "EQ" + } + } +} +''' + +QUERY_10_FIELDS_5_LSI_RQ5 = ''' +{ + "index_name": "AdditionalField3Index", + "key_conditions": { + "ForumName": { + "attribute_value_list": [ + { + "S": "MagnetoDB" + } + ], + "comparison_operator": "EQ" + }, + "AdditionalField3": { + "attribute_value_list": [ + { + "S": "%s" + } + ], + "comparison_operator": "EQ" + } + } +} +''' + + +QUERY_10_FIELDS_5_LSI_RQ6 = ''' +{ + "index_name": "AdditionalField4Index", + "key_conditions": { + "ForumName": { + "attribute_value_list": [ + { + "S": "MagnetoDB" + } + ], + "comparison_operator": "EQ" + }, + "AdditionalField4": { + "attribute_value_list": [ + { + "S": "%s" + } + ], + "comparison_operator": "EQ" + } + } +} +''' + +TEST_TABLE_NAME = "Thread" + + +QUERY_TEST_TABLE_RQ = """ +{ + "key_conditions": { + "ForumName": { + "attribute_value_list": [ + { + "S": "MagnetoDB" + } + ], + "comparison_operator": "EQ" + } + } +} +""" + +CREATE_TEST_TABLE_RQ = ''' +{ + "table_name": "Thread", + "attribute_definitions": [ + { + "attribute_name": "ForumName", + "attribute_type": "S" + }, + { + "attribute_name": "Subject", + "attribute_type": "S" + }, + { + "attribute_name": "LastPostedBy", + "attribute_type": "S" + } + ], + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "Subject", + "key_type": "RANGE" + } + ], + "local_secondary_indexes": [ + { + "index_name": "LastPostedByIndex", + "key_schema": [ + { + "attribute_name": "ForumName", + "key_type": "HASH" + }, + { + "attribute_name": "LastPostedBy", + "key_type": "RANGE" + } + ], + "projection": { + "projection_type": "ALL" + } + } + ] +} +''' + +PUT_ITEM_TEST_TABLE_RQ = ''' +{ + "item": { + "ForumName": {"S": "MagnetoDB"}, + "Subject": {"S": "%s"}, + "LastPostedBy": {"S": "test_user@magnetodb"}, + "Tags": {"SS": ["Update","Multiple Items","HelpMe"]}, + "ViewsCount": {"N": "0"} + } +} +''' + +DELETE_ITEM_TEST_TABLE_RQ = ''' +{ + "key": { + "ForumName": {"S": "MagnetoDB"}, + "Subject": {"S": "%s"} + } +} +''' + +GET_ITEM_TEST_TABLE_RQ = ''' +{ + "key": { + "ForumName": { + "S": "MagnetoDB" + }, + "Subject": { + "S": "%s" + } + }, + "attributes_to_get": ["LastPostedBy", "ViewsCount", "Tags"], + "consistent_read": true +} +''' + +GET_TOKEN_RQ = ''' +{ + "auth": { + "identity": { + "methods": [ + "password" + ], + "password": { + "user": { + "domain": { + "name": "%s" + }, + "name": "%s", + "password": "%s" + } + } + }, + "scope": { + "project": { + "domain": { + "name": "%s" + }, + "name": "%s" + } + } + } +} +''' diff --git a/tests/list_tables/scenario.py b/tests/list_tables/scenario.py new file mode 100644 index 0000000..f7b5379 --- /dev/null +++ b/tests/list_tables/scenario.py @@ -0,0 +1,71 @@ +import random +import locust +import time +import json +from gevent import GreenletExit +from locust.events import EventHook +from locust import task + +import config as cfg +import ks_config as kscfg + +PROJECT_ID = kscfg.PROJECT_ID + + +class UserBehavior(locust.TaskSet): + def on_start(self): + pass + + def on_stop(self): + pass + + def run(self, *args, **kwargs): + try: + super(UserBehavior, self).run(args, kwargs) + except GreenletExit: + if hasattr(self, "on_stop"): + self.on_stop() + raise + + @task(1) + def list_tables(self): + req_url = ('/v1/' + + PROJECT_ID + + '/data/tables') + self.client.get(req_url, headers=kscfg.req_headers, + name="list_tables") + + @task(1) + def list_tables_with_limit(self): + req_url = ('/v1/' + + PROJECT_ID + + '/data/tables?limit=' + cfg.LIMIT) + self.client.get(req_url, headers=kscfg.req_headers, + name="list_tables_with_limit_" + cfg.LIMIT) + + +class MagnetoDBUser(locust.HttpLocust): + task_set = UserBehavior + min_wait = cfg.MIN_WAIT + max_wait = cfg.MAX_WAIT + + +IS_FIRST_RUN = True + + +# Master code +def on_slave_report(client_id, data): + global IS_FIRST_RUN + runner = locust.runners.locust_runner + + if IS_FIRST_RUN and runner.slave_count == cfg.SLAVE_COUNT: + runner.start_hatching(cfg.LOCUST_COUNT, cfg.HATCH_RATE) + IS_FIRST_RUN = False + + num_rq = sum([val.num_requests + val.num_failures for val in + runner.request_stats.itervalues()]) + if runner.num_requests and num_rq >= runner.num_requests: + raise KeyboardInterrupt() + + +locust.events.slave_report += on_slave_report diff --git a/tests/list_tables/setup.py b/tests/list_tables/setup.py new file mode 100644 index 0000000..58dac37 --- /dev/null +++ b/tests/list_tables/setup.py @@ -0,0 +1,126 @@ +import os +import json +import random +import string +import requests +from subprocess import Popen, PIPE, STDOUT +import time +import config as cfg +import ks_config as kscfg +import queries as qry + + +def get_token_project(keystone_url, user, password, domain_name, project_name): + body = qry.GET_TOKEN_RQ % (domain_name, user, password, domain_name, project_name) + resp = requests.post(keystone_url, body, headers=cfg.token_req_headers) + if resp.status_code != 201: + raise Exception("Unable to get Keystone token") + token = resp.headers['X-Subject-Token'] + project_id = json.loads(resp.content)['token']['project']['id'] + with open(cfg.TOKEN_PROJECT, 'w') as token_proj: + json.dump({"token": token, "project_id": project_id}, token_proj) + return token, project_id + + +def create_table_helper(host, project_id, table_name, body): + req_url = (host + '/v1/' + + project_id + + '/data/tables/' + table_name) + resp = requests.get(req_url, headers=kscfg.req_headers) + if resp.status_code == 400 and "already exists" in resp.content: + pass + else: + req_url = (host + '/v1/' + + project_id + + '/data/tables') + requests.post(req_url, + body, + headers=kscfg.req_headers) + count = 0 + while count < 100: + req_url = (host + '/v1/' + + project_id + + '/data/tables/' + table_name) + resp = requests.get(req_url, headers=kscfg.req_headers) + if resp.status_code != 200 or "ACTIVE" in resp.content: + break + else: + count += 1 + time.sleep(1) + print "created table %s" % (table_name) + + +def random_name(length): + return ''.join(random.choice(string.lowercase + string.digits) + for i in range(length)) + + +def create_tables(host, project_id, + table_3_fields_no_lsi_list, + count_table_3_fields_no_lsi, + table_3_fields_1_lsi_list, + count_table_3_fields_1_lsi, + table_10_fields_5_lsi_list, + count_table_10_fields_5_lsi): + for i in xrange(count_table_3_fields_no_lsi): + table_name = random_name(20) + table_3_fields_no_lsi_list.append(table_name) + create_table_helper(host, project_id, table_name, + qry.CREATE_TABLE_3_FIELDS_NO_LSI_RQ % table_name) + + for i in xrange(count_table_3_fields_1_lsi): + table_name = random_name(20) + table_3_fields_1_lsi_list.append(table_name) + create_table_helper(host, project_id, table_name, + qry.CREATE_TABLE_3_FIELDS_1_LSI_RQ % table_name) + + for i in xrange(count_table_10_fields_5_lsi): + table_name = random_name(20) + table_10_fields_5_lsi_list.append(table_name) + create_table_helper(host, project_id, table_name, + qry.CREATE_TABLE_10_FIELDS_5_LSI_RQ % table_name) + # dump tables created + tables = { + "table_3_fields_no_lsi": table_3_fields_no_lsi_list, + "table_3_fields_1_lsi": table_3_fields_1_lsi_list, + "table_10_fields_5_lsi": table_10_fields_5_lsi_list + } + with open(cfg.TABLE_LIST, 'w') as table_files: + json.dump(tables, table_files) + + +def cassandra_cleanup(): + if os.path.isfile(cfg.CASSANDRA_CLEANER): + my_env = os.environ.copy() + my_env['CASSANDRA_NODE_LIST'] = cfg.CASSANDRA_NODES + p = Popen([cfg.CASSANDRA_CLEANER, '-d'], stdout=PIPE, + stdin=PIPE, stderr=STDOUT, env=my_env) + stdout = p.communicate(input='y')[0] + print stdout + + +def setup(host, keystone_url, user, password, domain_name, project_name): + print('Clean C*...') + cassandra_cleanup() + + print("Initializing ...") + token, project_id = get_token_project(keystone_url, user, password, + domain_name, project_name) + kscfg.TOKEN = token + kscfg.PROJECT_ID = project_id + kscfg.req_headers['X-Auth-Token'] = token + + table_3_fields_no_lsi_list = [] + table_3_fields_1_lsi_list = [] + table_10_fields_5_lsi_list = [] + count_table_3_fields_no_lsi = cfg.TABLES_CREATED_3_FIELDS_NO_LSI + count_table_3_fields_1_lsi = cfg.TABLES_CREATED_3_FIELDS_1_LSI + count_table_10_fields_5_lsi = cfg.TABLES_CREATED_10_FIELDS_5_LSI + create_tables(host, project_id, + table_3_fields_no_lsi_list, + count_table_3_fields_no_lsi, + table_3_fields_1_lsi_list, + count_table_3_fields_1_lsi, + table_10_fields_5_lsi_list, + count_table_10_fields_5_lsi) + print ("Done.") diff --git a/tests/list_tables/teardown.py b/tests/list_tables/teardown.py new file mode 100644 index 0000000..32059e5 --- /dev/null +++ b/tests/list_tables/teardown.py @@ -0,0 +1,41 @@ +import json +import time + +import requests +import config as cfg +import ks_config as kscfg + + +def cleanup(host): + print "Clean up ..." + with open(cfg.TABLE_LIST) as table_list_file: + table_list = json.load(table_list_file) + + table_types = table_list.keys() + for table_type in table_types: + table_name_set = table_list[table_type] + for table_name in table_name_set: + req_url = (host + '/v1/' + + kscfg.PROJECT_ID + + '/data/tables/' + table_name) + resp = requests.get(req_url, headers=kscfg.req_headers) + if resp.status_code != 200 or "DELETING" in resp.content: + continue + + req_url = (host + '/v1/' + + kscfg.PROJECT_ID + + '/data/tables/' + table_name) + requests.delete(req_url, headers=kscfg.req_headers) + count = 0 + while count < 100: + req_url = (host + '/v1/' + + kscfg.PROJECT_ID + + '/data/tables/' + table_name) + resp = requests.get(req_url, headers=kscfg.req_headers) + if resp.status_code != 200: + print "deleted table %s" % table_name + break + else: + time.sleep(1) + count += 1 + print "Done."