From 1744a78d4450eaea9706ebfaccd505a4ac11f2b8 Mon Sep 17 00:00:00 2001 From: Andrei-Adnan Ismail Date: Mon, 28 Dec 2015 08:42:10 +0200 Subject: [PATCH 1/4] #454 First draft of scenarios tool. --- scenarios.py | 101 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100755 scenarios.py diff --git a/scenarios.py b/scenarios.py new file mode 100755 index 000000000..a1b7b5a5f --- /dev/null +++ b/scenarios.py @@ -0,0 +1,101 @@ +#!/usr/bin/python + +"""scenarios management tool + +Usage: + scenarios.py [...] + scenarios.py start [] + scenarios.py build_image [] + +The most commonly used scenarios.py commands are: + list List the available test scenarios + proxysql_versions List the available ProxySQL versions to be tested + mysql_versions List the available MySQL versions to be paired with ProxySQL for testing + start Start a ProxySQL testing scenario + ps List the running ProxySQL scenarios +""" +import os +import subprocess + +from docopt import docopt + +from test.docker_fleet import DockerFleet + +def scenarios_list(): + templates = DockerFleet().get_docker_scenario_templates() + scenario_names = sorted(templates.keys()) + for scenario in scenario_names: + print('%s @ %s' % (scenario, os.path.abspath(templates[scenario]['dir']))) + +def proxysql_images(): + dockerfiles = DockerFleet().get_dockerfiles_for_proxysql() + images = sorted(dockerfiles.keys()) + for image in images: + print('%s @ %s' % (image, os.path.abspath(dockerfiles[image]['dir']))) + +def mysql_images(): + dockerfiles = DockerFleet().get_dockerfiles_for_mysql() + images = sorted(dockerfiles.keys()) + for image in images: + print('%s @ %s' % (image, os.path.abspath(dockerfiles[image]['dir']))) + +def start(scenario, proxysql_version, mysql_version): + # TODO(andrei): store somewhere details so that we don't need to pass + # any args to stop(), making it easier + pass + +def stop(): + pass + +def _build_image(image, dir): + subprocess.call(["docker", "rmi", "-f", "proxysql:%s" % image]) + subprocess.call(["docker", "build", "-t", "proxysql:%s" % image, "."], + cwd=dir) + +def build_image(image): + if image != 'all': + # Builds a docker image (either for ProxySQL or for MySQL) and commits it + # to the renecannao dockerhub repository. + dockerfiles = DockerFleet().get_dockerfiles_for_proxysql() + if image in dockerfiles: + _build_image(image, dockerfiles[image]['dir']) + return + + dockerfiles = DockerFleet().get_dockerfiles_for_mysql() + if image in dockerfiles: + _build_image(image, dockerfiles[image]['dir']) + return + + print("Image %s wasn't found in either ProxySQL or MySQL image list.\n" + "Please double-check the name!" % image) + else: + dockerfiles = DockerFleet().get_dockerfiles_for_proxysql() + for image in dockerfiles.iterkeys(): + _build_image(image, dockerfiles[image]['dir']) + + dockerfiles = DockerFleet().get_dockerfiles_for_mysql() + for image in dockerfiles.iterkeys(): + _build_image(image, dockerfiles[image]['dir']) + +if __name__ == '__main__': + + args = docopt(__doc__, + version='scenarios.py version 0.0.1', + options_first=True) + + argv = [args['']] + args[''] + if args[''] == 'list': + scenarios_list() + elif args[''] == 'proxysql_images': + proxysql_images() + elif args[''] == 'mysql_images': + mysql_images() + elif args[''] == 'start': + start() + elif args[''] == 'stop': + stop() + elif args[''] == 'build_image': + if len(args['']) > 0: + build_image(args[''][0]) + else: + build_image('all') \ No newline at end of file From e8b289aaa3db1924142a4cfa07f0102af87d542f Mon Sep 17 00:00:00 2001 From: Andrei-Adnan Ismail Date: Mon, 4 Jan 2016 13:42:35 +0200 Subject: [PATCH 2/4] #454 Add start & stop scenario commands --- scenarios.py | 55 +++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/scenarios.py b/scenarios.py index a1b7b5a5f..cf1ab32e6 100755 --- a/scenarios.py +++ b/scenarios.py @@ -21,6 +21,8 @@ from docopt import docopt from test.docker_fleet import DockerFleet +PROXYSQL_SCENARIO_FILE = '/tmp/proxysql-scenario.txt' + def scenarios_list(): templates = DockerFleet().get_docker_scenario_templates() scenario_names = sorted(templates.keys()) @@ -39,13 +41,22 @@ def mysql_images(): for image in images: print('%s @ %s' % (image, os.path.abspath(dockerfiles[image]['dir']))) -def start(scenario, proxysql_version, mysql_version): - # TODO(andrei): store somewhere details so that we don't need to pass - # any args to stop(), making it easier - pass +def start(scenario, proxysql_image, mysql_image): + docker_fleet = DockerFleet() + scenario_info = docker_fleet.generate_scenarios( + scenarios=[scenario], + proxysql_filters={'names': [proxysql_image]}, + mysql_filters={'names': [mysql_image]} + )[0] + dirname = docker_fleet.start_temp_scenario(scenario_info, copy_folder=True) + with open(PROXYSQL_SCENARIO_FILE, 'wt') as f: + f.write(dirname) + return dirname def stop(): - pass + with open(PROXYSQL_SCENARIO_FILE, 'rt') as f: + dirname = ''.join(f.readlines()).strip() + DockerFleet().stop_temp_scenario(dirname, delete_folder=True) def _build_image(image, dir): subprocess.call(["docker", "rmi", "-f", "proxysql:%s" % image]) @@ -91,9 +102,39 @@ if __name__ == '__main__': elif args[''] == 'mysql_images': mysql_images() elif args[''] == 'start': - start() + if len(args['']) >= 1: + scenario = args[''][0] + else: + # Default value for the scenario parameter: '1backend' + scenario = '1backend' + + if len(args['']) >= 2: + proxysql_image = args[''][1].split('=')[1] + else: + # Default value for the proxysql_image parameter: 'proxysql' + proxysql_image = 'proxysql' + + if len(args['']) >= 3: + mysql_image = args[''][2].split('=')[1] + else: + # Default value for the mysql_image parameter: 'mysql-simple-dump' + mysql_image = 'mysql-simple-dump' + + if (os.path.exists(PROXYSQL_SCENARIO_FILE)): + print("Is there another scenario running? If not, delete %s" % + PROXYSQL_SCENARIO_FILE) + else: + dirname = start(scenario, proxysql_image, mysql_image) + print("Scenario started successfully at path %s" % dirname) + elif args[''] == 'stop': - stop() + if (not os.path.exists(PROXYSQL_SCENARIO_FILE)): + print("There is no scenario running or file %s has been removed" % + PROXYSQL_SCENARIO_FILE) + else: + stop() + print("Scenario stopped successfully") + elif args[''] == 'build_image': if len(args['']) > 0: build_image(args[''][0]) From a5df0744420dd428f79eee3972ba60543cd1a69d Mon Sep 17 00:00:00 2001 From: Andrei-Adnan Ismail Date: Mon, 4 Jan 2016 14:22:52 +0200 Subject: [PATCH 3/4] #454 Add command to run nose tests --- scenarios.py | 17 +++++++++++++++- test/admin_tables_test.py | 7 ++----- test/admin_test.py | 7 ++----- test/authentication_test.py | 22 +++++---------------- test/one_backend_test.py | 7 ++----- test/replication_topology_awareness_test.py | 4 +++- test/sysbench_test.py | 5 +---- 7 files changed, 31 insertions(+), 38 deletions(-) diff --git a/scenarios.py b/scenarios.py index cf1ab32e6..e49951a5e 100755 --- a/scenarios.py +++ b/scenarios.py @@ -16,8 +16,10 @@ The most commonly used scenarios.py commands are: """ import os import subprocess +import sys from docopt import docopt +import nose from test.docker_fleet import DockerFleet @@ -57,6 +59,10 @@ def stop(): with open(PROXYSQL_SCENARIO_FILE, 'rt') as f: dirname = ''.join(f.readlines()).strip() DockerFleet().stop_temp_scenario(dirname, delete_folder=True) + try: + os.remove(PROXYSQL_SCENARIO_FILE) + except: + pass def _build_image(image, dir): subprocess.call(["docker", "rmi", "-f", "proxysql:%s" % image]) @@ -88,6 +94,9 @@ def build_image(image): for image in dockerfiles.iterkeys(): _build_image(image, dockerfiles[image]['dir']) +def test(): + nose.run(argv=['.']) + if __name__ == '__main__': args = docopt(__doc__, @@ -139,4 +148,10 @@ if __name__ == '__main__': if len(args['']) > 0: build_image(args[''][0]) else: - build_image('all') \ No newline at end of file + build_image('all') + + elif args[''] == 'test': + if (not os.path.exists(PROXYSQL_SCENARIO_FILE)): + print("There doesn't seem to be a running scenario. Aborting.") + else: + test() \ No newline at end of file diff --git a/test/admin_tables_test.py b/test/admin_tables_test.py index 47bdf5614..fd1e70a61 100644 --- a/test/admin_tables_test.py +++ b/test/admin_tables_test.py @@ -5,7 +5,7 @@ from proxysql_base_test import ProxySQLBaseTest class AdminTablesTest(ProxySQLBaseTest): - def _test_monitor_tables_locking_errors(self): + def test_monitor_tables_locking_errors(self): """Test that intensive read/write operations to the MySQL Monitor tables do not trigger locking errors. @@ -31,7 +31,4 @@ class AdminTablesTest(ProxySQLBaseTest): # If we reached this point without an error, it means that the test # has passed. - self.assertEqual(1, 1) - - def test_monitor_tables_locking_errors(self): - self.run_in_docker_scenarios(self._test_monitor_tables_locking_errors) \ No newline at end of file + self.assertEqual(1, 1) \ No newline at end of file diff --git a/test/admin_test.py b/test/admin_test.py index 1b7aca353..2fe4e0bdd 100644 --- a/test/admin_test.py +++ b/test/admin_test.py @@ -4,7 +4,7 @@ from MySQLdb import OperationalError class AdminTest(ProxySQLBaseTest): - def _test_stop_main_thread(self): + def test_stop_main_thread(self): try: # This test will just assert that PROXYSQL STOP works correctly # Since September 2015, the behaviour has been changed - PROXYSQL STOP @@ -13,7 +13,4 @@ class AdminTest(ProxySQLBaseTest): self.run_query_proxysql_admin("PROXYSQL STOP") self.assertEqual(0, 1) except OperationalError: - self.assertEqual(1, 1) - - def test_stop_main_thread(self): - self.run_in_docker_scenarios(self._test_stop_main_thread) \ No newline at end of file + self.assertEqual(1, 1) \ No newline at end of file diff --git a/test/authentication_test.py b/test/authentication_test.py index d6ef7c158..4bd747429 100644 --- a/test/authentication_test.py +++ b/test/authentication_test.py @@ -6,7 +6,7 @@ from proxysql_base_test import ProxySQLBaseTest class AuthenticationTest(ProxySQLBaseTest): - def _test_existing_user_with_correct_password_works(self): + def test_existing_user_with_correct_password_works(self): version1 = self.run_query_mysql( "SELECT @@version_comment LIMIT 1", "test", return_result=True, @@ -19,10 +19,7 @@ class AuthenticationTest(ProxySQLBaseTest): self.assertEqual(version1, version2) - def test_existing_user_with_correct_password_works(self): - self.run_in_docker_scenarios(self._test_existing_user_with_correct_password_works) - - def _test_existing_user_with_correct_password_but_not_registerd_within_proxysql_does_not_work(self): + def test_existing_user_with_correct_password_but_not_registerd_within_proxysql_does_not_work(self): try: self.run_query_proxysql("SELECT @@version_comment LIMIT 1", "test", return_result=True, @@ -33,10 +30,7 @@ class AuthenticationTest(ProxySQLBaseTest): except OperationalError: self.assertEqual(1, 1) - def test_existing_user_with_correct_password_but_not_registerd_within_proxysql_does_not_work(self): - self.run_in_docker_scenarios(self._test_existing_user_with_correct_password_works) - - def _test_existing_user_with_incorrect_password_does_not_work(self): + def test_existing_user_with_incorrect_password_does_not_work(self): try: self.run_query_proxysql("SELECT @@version_comment LIMIT 1", "test", return_result=True, @@ -47,17 +41,11 @@ class AuthenticationTest(ProxySQLBaseTest): except OperationalError: self.assertEqual(1, 1) - def test_existing_user_with_incorrect_password_does_not_work(self): - self.run_in_docker_scenarios(self._test_existing_user_with_incorrect_password_does_not_work) - - def _test_inexisting_user_with_random_password_does_not_work(self): + def test_inexisting_user_with_random_password_does_not_work(self): try: self.run_query_proxysql("SELECT @@version_comment LIMIT 1", "test", return_result=True, username="johnny", password="randomdoe") self.assertEqual(1, 0) except OperationalError: - self.assertEqual(1, 1) - - def test_inexisting_user_with_random_password_does_not_work(self): - self.run_in_docker_scenarios(self._test_inexisting_user_with_random_password_does_not_work) \ No newline at end of file + self.assertEqual(1, 1) \ No newline at end of file diff --git a/test/one_backend_test.py b/test/one_backend_test.py index af02d7e25..643a3d016 100644 --- a/test/one_backend_test.py +++ b/test/one_backend_test.py @@ -4,11 +4,8 @@ from proxysql_base_test import ProxySQLBaseTest class OneBackendTest(ProxySQLBaseTest): - def _test_select_strings_returns_correct_result(self): + def test_select_strings_returns_correct_result(self): rows = self.run_query_proxysql("SELECT * FROM strings", "test") self.assertEqual(set([row[0] for row in rows]), - set(['a', 'ab', 'abc', 'abcd'])) - - def test_select_strings_returns_correct_result(self): - self.run_in_docker_scenarios(self._test_select_strings_returns_correct_result) \ No newline at end of file + set(['a', 'ab', 'abc', 'abcd'])) \ No newline at end of file diff --git a/test/replication_topology_awareness_test.py b/test/replication_topology_awareness_test.py index 97134b47a..f7bac7d77 100644 --- a/test/replication_topology_awareness_test.py +++ b/test/replication_topology_awareness_test.py @@ -6,6 +6,7 @@ import time from proxysql_base_test import ProxySQLBaseTest +""" class ReplicationTopologyAwareness(ProxySQLBaseTest): def _test_insert_sent_through_proxysql_is_visible_in_slave_servers(self): @@ -177,4 +178,5 @@ class ReplicationTopologyAwareness(ProxySQLBaseTest): # The old master, and the other slaves should still be in the slave hostgroup for ip in slave_ips: - self.assertEqual(hostgroups[ip], 1) \ No newline at end of file + self.assertEqual(hostgroups[ip], 1) +""" \ No newline at end of file diff --git a/test/sysbench_test.py b/test/sysbench_test.py index 2bef5762b..168576238 100644 --- a/test/sysbench_test.py +++ b/test/sysbench_test.py @@ -2,8 +2,5 @@ from proxysql_base_test import ProxySQLBaseTest class SysBenchTest(ProxySQLBaseTest): - def _test_proxy_doesnt_crash_under_mild_sysbench_load(self): - self.run_sysbench_proxysql() - def test_proxy_doesnt_crash_under_mild_sysbench_load(self): - self.run_in_docker_scenarios(self._test_proxy_doesnt_crash_under_mild_sysbench_load) \ No newline at end of file + self.run_sysbench_proxysql() \ No newline at end of file From 49f0cf78b16a44f853990a3d683f5c0c1295c9d4 Mon Sep 17 00:00:00 2001 From: Andrei-Adnan Ismail Date: Wed, 6 Jan 2016 09:13:15 +0200 Subject: [PATCH 4/4] #454 Add testing command to scenarios tool. --- scenarios.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/scenarios.py b/scenarios.py index e49951a5e..445eb5575 100755 --- a/scenarios.py +++ b/scenarios.py @@ -94,8 +94,8 @@ def build_image(image): for image in dockerfiles.iterkeys(): _build_image(image, dockerfiles[image]['dir']) -def test(): - nose.run(argv=['.']) +def test(argv): + nose.run(argv=argv) if __name__ == '__main__': @@ -154,4 +154,7 @@ if __name__ == '__main__': if (not os.path.exists(PROXYSQL_SCENARIO_FILE)): print("There doesn't seem to be a running scenario. Aborting.") else: - test() \ No newline at end of file + if len(args['']) > 0: + test(args['']) + else: + test(['.']) \ No newline at end of file