def get_result(self): msg = [] copied_db_on_server2 = [ 'util_db_clone', 'util_test', 'util_test_multi', 'db`:db_clone', 'db`:db', 'views_test_clone', 'util_db_privileges', 'blob_test_clone', 'blob_test_multi', 'blob_test_no_backslash_escapes', 'util"test_copy', 'util"test_no_backslash_escapes' ] copied_db_on_server1 = [ "util_test_default_collation_copy", "util_test_default_charset_copy" ] # Check databases existence. query = "SHOW DATABASES LIKE '{0}'" for db in copied_db_on_server2: try: res = self.server2.exec_query(query.format(db)) try: if res[0][0] != db: msg.append("Database {0} not found in {1}.\n" "".format(db, self.server2.role)) except IndexError: msg.append("Database {0} not found in {1}.\n" "".format(db, self.server2.role)) except UtilDBError as err: raise MUTLibError(err.errmsg) for db in copied_db_on_server1: try: res = self.server1.exec_query(query.format(db)) try: if res[0][0] != db: msg.append("Database {0} not found in {1}.\n" "".format(db, self.server1.role)) except IndexError: msg.append("Database {0} not found in {1}.\n" "".format(db, self.server1.role)) except UtilDBError as err: raise MUTLibError(err.errmsg) # Compare table checksums. dbs2compare = [('`util_test`', ('`util_test`', '`util_db_clone`', '`util_test_multi`', '`util_db_privileges`')), ('`db``:db`', ('`db``:db`', '`db``:db_clone`')), ('`views_test`', ('`views_test_clone`', )), ('blob_test', ('blob_test_clone', 'blob_test_multi', 'blob_test_no_backslash_escapes'))] for cmp_data in dbs2compare: self.server1.exec_query("USE {0}".format(cmp_data[0])) res = self.server1.exec_query("SHOW TABLES") for row in res: table = quote_with_backticks(row[0], self.prev_sql_mode) base_checksum = self.server1.exec_query( "CHECKSUM TABLE {0}".format(table))[0][1] for i in range(len(cmp_data[1])): tbl_checksum = self.server2.exec_query( "CHECKSUM TABLE {0}.{1}".format(cmp_data[1][i], table))[0][1] if tbl_checksum != base_checksum: msg.append("Different table checksum for table " "{0}.{1}, got {2} expected " "{3}.".format(cmp_data[1][i], table, tbl_checksum, base_checksum)) # Check attributes (character set and collation). qry_db = ("SELECT {0} FROM INFORMATION_SCHEMA.SCHEMATA " "WHERE SCHEMA_NAME = '{1}'") qry_tb = ("SELECT CCSA.{0} " "FROM information_schema.`TABLES` T, " "information_schema.`COLLATION_CHARACTER_SET_APPLICABILITY`" " CCSA WHERE CCSA.collation_name = T.table_collation " " AND T.table_schema = '{1}' AND T.table_name = 't1'") check_db_info_on_server1 = [ ("util_test_default_collation_copy", "DEFAULT_COLLATION_NAME", "utf8_general_ci", "COLLATION_NAME"), ("util_test_default_charset_copy", "DEFAULT_CHARACTER_SET_NAME", "utf8", "CHARACTER_SET_NAME") ] for db in check_db_info_on_server1: try: res = self.server1.exec_query(qry_db.format(db[1], db[0])) try: if res[0][0] != db[2]: msg.append("For database {0} attribute {1} copy " "failed, got {2} expected {3}.\n" "".format(db[0], db[1], res[0][0], db[2])) except IndexError: msg.append("For database {0} no value found for attribute " "{1}.\n".format(db[0], db[1])) res = self.server1.exec_query(qry_tb.format(db[3], db[0])) try: if res[0][0] != db[2]: msg.append("For table {0} attribute {1} copy " "failed, got {2} expected {3}.\n" "".format(db[0], db[3], res[0][0], db[2])) except IndexError: msg.append("For table {0} no value found for attribute " "{1}.\n".format(db[0], db[3])) except UtilDBError as err: raise MUTLibError(err.errmsg) if msg: return False, ("Result failure.\n", "\n".join(msg)) else: return True, ""
def run(self): self.server1 = self.servers.get_server(0) self.res_fname = "result.txt" s1_conn = "--server1={0}".format( self.build_connection_string(self.server1)) s2_conn = "--server2={0}".format( self.build_connection_string(self.server2)) cmd_base = "mysqldiff.py {0} {1} util_test:util_test".format( s1_conn, s2_conn) test_num = 1 cmd_opts = "--help" comment = "Test case {0} - Use {1} ".format(test_num, cmd_opts) cmd = "{0} {1}".format(cmd_base, cmd_opts) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) for compacted in _COMPACT_OUTPUT: for frmt in _FORMATS: test_num += 1 cmd_opts = "--difftype={0}{1}".format(frmt, compacted) comment = "Test case {0} - Use diff {1}".format( test_num, cmd_opts) cmd = "{0} {1}".format(cmd_base, cmd_opts) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 cmd_opts = "--force" comment = "Test case {0} - Use {1} ".format(test_num, cmd_opts) cmd = "{0} {1}".format(cmd_base, cmd_opts) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 cmd_opts = "--quiet" comment = "Test case {0} - Use {1} ".format(test_num, cmd_opts) cmd = "{0} {1}".format(cmd_base, cmd_opts) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 cmd_opts = "--width=65" comment = "Test case {0} - Use {1} ".format(test_num, cmd_opts) cmd = "{0} {1}".format(cmd_base, cmd_opts) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 cmd_opts = "--width=55" comment = "Test case {0} - Use {1} ".format(test_num, cmd_opts) cmd = "{0} {1}".format(cmd_base, cmd_opts) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 cmd_opts = "-vvv" comment = "Test case {0} - Use {1} ".format(test_num, cmd_opts) cmd = "{0} {1}".format(cmd_base, cmd_opts) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Test --changes-for and reverse for direct in _DIRECTIONS: test_num += 1 cmd_opts = "--changes-for={0} ".format(direct) comment = "Test case {0} - Use {1} ".format(test_num, cmd_opts) cmd = "{0} {1}".format(cmd_base, cmd_opts) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # now with reverse test_num += 1 cmd_opts = "--changes-for={0} --show-reverse".format(direct) comment = "Test case {0} - Use {1} ".format(test_num, cmd_opts) cmd = "{0} {1}".format(cmd_base, cmd_opts) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Test use of --skip-table-options (different AUTO_INCREMENT) difftype_options = ['', '--difftype=context', '--difftype=sql'] cmd_base = ("mysqldiff.py {0} {1} " "db_diff_test:db_diff_test".format(s1_conn, s2_conn)) for difftype_opt in difftype_options: for direct in _DIRECTIONS: test_num += 1 comment = ("Test case {0}a - Changes for {1} {2} (not " "skipping table options).".format( test_num, direct, difftype_opt)) cmd = "{0} --changes-for={1} {2}".format( cmd_base, direct, difftype_opt) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) comment = ("Test case {0}b - Changes for {1} {2} (skipping " "table options).".format(test_num, direct, difftype_opt)) cmd = ("{0} --changes-for={1} {2} " "--skip-table-options".format(cmd_base, direct, difftype_opt)) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Now test for difftype=SQL and skip-table-options when there is # only one table with table options. self.server1.exec_query(_CREATE_FIRST_TABLE) self.server2.exec_query(_CREATE_SECOND_TABLE) test_num += 1 cmd = "{0}{1}{2}{3}{4} {5}".format("mysqldiff.py ", "--difftype=SQL ", "--skip-table-options ", "util_test.a1:util_test.a1 ", s1_conn, s2_conn) comment = "Test case {0} - Use --skip-table-options ".format(test_num) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # The following are necessary due to changes in character spaces # introduced with Python 2.7.X in the difflib. self.replace_result("+++ util_test.t1", "+++ util_test.t1\n") self.replace_result("+++ util_test.t2", "+++ util_test.t2\n") self.replace_result("--- util_test.t1", "--- util_test.t1\n") self.replace_result("--- util_test.t2", "--- util_test.t2\n") self.replace_result("*** util_test.t1", "*** util_test.t1\n") self.replace_result("*** util_test.t2", "*** util_test.t2\n") self.replace_substring("on [::1]", "on localhost") # Mask version self.replace_result("MySQL Utilities mysqldiff version", "MySQL Utilities mysqldiff version X.Y.Z\n") return True
def check_prerequisites(self): # Check MySQL server version - Must be 5.6.9 or higher if not self.servers.get_server(0).check_version_compat(5, 6, 9): raise MUTLibError("Test requires server version 5.6.9 or higher") return self.check_num_servers(1)
def run(self): self.res_fname = "result.txt" server_conn = "--server={0}".format( self.build_connection_string(self.server2)) master_conn = "--master={0}".format( self.build_connection_string(self.server2)) self.res_fname = "result.txt" server_conn3 = "--server={0}".format( self.build_connection_string(self.server3)) master_conn3 = "--master={0}".format( self.build_connection_string(self.server3)) cmd_str = "mysqlbinlogpurge.py {0}" test_num = 1 comment = ("Test case {0} - No options" "".format(test_num)) cmd = "mysqlbinlogpurge.py" res = self.run_test_case(2, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - Master no Slave options" "".format(test_num)) cmd = cmd_str.format(master_conn) res = self.run_test_case(2, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - Server with Slave option" "".format(test_num)) cmd = "{0} --slave={1}".format( cmd_str.format(server_conn), self.build_connection_string(self.server2)) res = self.run_test_case(2, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - Server without binlog" "".format(test_num)) cmd = "{0} ".format(cmd_str.format(server_conn3), self.build_connection_string(self.server2)) res = self.run_test_case(1, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - Master with wrong Slave" "".format(test_num)) cmd = "{0} --slave={1}".format( cmd_str.format(master_conn3), self.build_connection_string(self.server2)) res = self.run_test_case(1, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - Server with Discover option" "".format(test_num)) cmd = "{0} --discover={1}".format(cmd_str.format(server_conn), "root:rootpass") res = self.run_test_case(2, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - Only discover option" "".format(test_num)) cmd = "mysqlbinlogpurge.py --discover={0}".format("root:rootpass") res = self.run_test_case(2, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - Only slaves option" "".format(test_num)) cmd = "mysqlbinlogpurge.py --slaves={0}".format(server_conn) res = self.run_test_case(2, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - Only dry-run and verbose options" "".format(test_num)) cmd = "{0} -vv -d".format("mysqlbinlogpurge.py") res = self.run_test_case(2, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - wrong binlog base name" "".format(test_num)) cmd = "{0} --binlog={1}".format(cmd_str.format(server_conn), "wrong_binlog_name.00002") res = self.run_test_case(1, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - server and master options mixed" "".format(test_num)) cmd = "{0} {1}".format(cmd_str.format(server_conn), master_conn) res = self.run_test_case(2, cmd, comment) if not res or not binlog_file_exists(self.server2_datadir, "mysql-bin.000001", self.debug): raise MUTLibError("{0}: failed".format(comment)) # Mask results self.replace_substring("localhost", "XXXX-XXXX") p_n = 0 for port in self.mask_ports: p_n += 1 self.replace_substring(repr(port), "PORT{0}".format(p_n)) return True
def run(self): # Get the engines for the tables and save them for compare # # Note: This may show different result file if run on a server whose # default storage engine is set differently than version 5.1. # def _get_engines(): for table_name in _TABLES: res = self.server1.exec_query(_ENGINE_QUERY % table_name) if res == []: self.results.append("util_test.%s: ENGINE NOT FOUND!\n") else: self.results.append("util_test.%s: ENGINE=%s\n" % (table_name, res[0][0])) self.res_fname = "result.txt" import_basic.test.drop_all(self) to_conn = "--server=" + self.build_connection_string(self.server1) import_file = os.path.normpath("./std_data/bad_engine.csv") case_num = 1 cmd_str = "mysqldbimport.py %s %s --import=both --format=CSV " % \ (to_conn, import_file) comment = "Test case %d - Normal run" % case_num res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 _get_engines() cmd_str = "mysqldbimport.py %s %s --import=definitions " % \ (to_conn, import_file) cmd_str += "--new-storage-engine=MEMORY --drop-first --format=CSV" comment = "Test case %d - convert to memory storage engine" % case_num res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 _get_engines() cmd_str = "mysqldbimport.py %s %s --import=definitions " % \ (to_conn, import_file) cmd_str += "--new-storage-engine=NOTTHERE --drop-first --format=CSV" comment = "Test case %d - new storage engine missing" % case_num res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 _get_engines() cmd_str = "mysqldbimport.py %s %s --import=definitions " % \ (to_conn, import_file) cmd_str += "--default-storage-engine=NOPENOTHERE --drop-first" + \ " --format=CSV" comment = "Test case %d - default storage engine missing" % case_num res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 _get_engines() cmd_str = "mysqldbimport.py %s %s --import=definitions " % \ (to_conn, import_file) cmd_str += "--new-storage-engine=NOTTHERE --drop-first --format=CSV " cmd_str += "--default-storage-engine=INNODB " comment = "Test case %d - new storage engine missing, default Ok" % \ case_num res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 _get_engines() cmd_str = "mysqldbimport.py %s %s --import=definitions " % \ (to_conn, import_file) cmd_str += "--default-storage-engine=NOPENOTHERE --drop-first" + \ " --format=CSV " cmd_str += "--new-storage-engine=MYISAM" comment = "Test case %d - default storage engine missing, new Ok" % \ case_num res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 _get_engines() self.replace_result("# Importing", "# Importing ... bad_engines.csv\n") return True
def check_prerequisites(self): if self.servers.get_server(0).check_version_compat(5, 6, 5): raise MUTLibError("Test requires server version prior to 5.6.5") return copy_db_rpl.test.check_prerequisites(self)
class test(import_basic.test): """check parameters for import utility This test executes a basic check of parameters for mysqldbimport. It uses the import_basic test as a parent for setup and teardown methods. """ def check_prerequisites(self): return import_basic.test.check_prerequisites(self) def setup(self): return import_basic.test.setup(self) def do_skip_test(self, cmd_str, comment, expected_res=0): # Precheck: check db and save the results. self.results.append("BEFORE:\n") self.results.append(self.check_objects(self.server2, "util_test")) res = self.run_test_case(expected_res, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) # Now, check db and save the results. self.results.append("AFTER:\n") res = self.server2.exec_query("SHOW DATABASES LIKE 'util_test'") if res == () or res == []: self.results.append("Database was NOT created.\n") else: self.results.append("Database was created.\n") self.results.append(self.check_objects(self.server2, "util_test")) try: self.drop_db(self.server2, "util_test") except: pass # ok if this fails - it is a spawned server def run(self): self.res_fname = "result.txt" from_conn = "--server=" + self.build_connection_string(self.server1) to_conn = "--server=" + self.build_connection_string(self.server2) cmd_str = "mysqldbimport.py %s %s --import=definitions " % \ (to_conn, self.export_import_file) cmd_opts = " --help" comment = "Test case 1 - help" res = self.run_test_case(0, cmd_str + cmd_opts, comment) if not res: raise MUTLibError("%s: failed" % comment) # Now test the skips # Note: data and blobs must be done separately _SKIPS = ("grants", "events", "functions", "procedures", "triggers", "views", "tables", "create_db") _FORMATS = ("CSV", "SQL") case_num = 2 for format in _FORMATS: # Create an import file export_cmd = "mysqldbexport.py %s util_test --export=BOTH " % \ from_conn + " --skip-gtid " export_cmd += "--format=%s --display=BRIEF > %s " % \ (format, self.export_import_file) comment = "Generating import file" res = self.run_test_case(0, export_cmd, comment) if not res: raise MUTLibError("%s: failed" % comment) cmd_opts = "%s --format=%s --skip=" % (cmd_str, format) for skip in _SKIPS: if case_num != 2 and case_num != 2 + len(_SKIPS): cmd_opts += "," cmd_opts += "%s" % skip comment = "Test case %d - no %s" % (case_num, skip) self.do_skip_test(cmd_opts, comment) case_num += 1 # Now test --skip=data, --skip-blobs # Create an import file with blobs try: res = self.server1.exec_query("ALTER TABLE util_test.t3 " "ADD COLUMN me_blob BLOB") res = self.server1.exec_query("UPDATE util_test.t3 SET " "me_blob = 'This, is a BLOB!'") except UtilDBError, e: raise MUTLibError("Failed to add blob column: %s" % e.errmsg) export_cmd = "mysqldbexport.py %s util_test --export=BOTH " % \ from_conn + " --skip-gtid " export_cmd += "--format=%s --display=BRIEF > %s " % \ ("CSV", self.export_import_file) comment = "Generating import file" res = self.run_test_case(0, export_cmd, comment) if not res: raise MUTLibError("%s: failed" % comment) # No skips for reference (must skip events for deterministic reasons cmd_str = "mysqldbimport.py %s %s --import=both --dryrun " % \ (to_conn, self.export_import_file) cmd_str += " --format=CSV --bulk-insert " comment = "Test case %d - no %s" % (case_num, "events") res = self.run_test_case(0, cmd_str + "--skip=events", comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 cmd_str = "mysqldbimport.py %s %s --import=both --dryrun " % \ (to_conn, self.export_import_file) cmd_str += " --format=CSV --bulk-insert " comment = "Test case %d - no %s" % (case_num, "data") res = self.run_test_case(0, cmd_str + "--skip=events,data", comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 cmd_str = "mysqldbimport.py %s %s --import=both --dryrun " % \ (to_conn, self.export_import_file) cmd_str += " --format=CSV --skip-blobs --bulk-insert " comment = "Test case %d - no %s" % (case_num, "blobs") res = self.run_test_case(0, cmd_str + "--skip=events", comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 # Lastly, do a quiet import cmd_str = "mysqldbimport.py %s %s --import=both --quiet " % \ (to_conn, self.export_import_file) cmd_str += " --format=CSV --bulk-insert " comment = "Test case %d - no %s" % (case_num, "messages (quiet)") res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) case_num += 1 return True
def run(self): self.res_fname = "result.txt" conn_str = self.build_connection_string(self.server1, ssl=True) conn_str_nossl = self.build_connection_string(self.server1, ssl=False) conn_ssl_opt = self.build_custom_connection_string(self.server1, 'ssl_opt', 'ssl_opt_pass') tests = [] # ======== mysqlindexcheck ========= # tests.append({ "utility": "mysqlindexcheck", "cmd_str": "mysqlindexcheck.py --server={0}", "comment": ("Test case {0} {1} - indexcheck with ssl connection " "all tables for a single database"), "cmd_opts": "util_test_a" }) # ======== mysqlserverinfo ========= # tests.append({ "utility": "mysqlserverinfo", "cmd_str": "mysqlserverinfo.py --server={0}", "comment": "Test case {0} {1} - basic serverinfo with ssl", "cmd_opts": " --format=vertical " }) # ======== mysqluserclone ========= # tests.append({ "utility": "mysqluserclone", "cmd_str": "mysqluserclone.py --source={0}", "comment": "Test case {0} {1} - userclone dump grants with ssl", "cmd_opts": " -d -v {0}".format(" joe_pass@user") }) # ======== mysqldbexport ========= # tests.append({ "utility": "mysqldbexport", "cmd_str": "mysqldbexport.py --server={0}", "comment": "Test case {0} {1} - basic dbexport with ssl", "cmd_opts": " -edefinitions {0}".format("util_test_a") }) # ======== mysqldbimport ========= # tests.append({ "utility": "mysqldbimport", "cmd_str": "mysqldbimport.py --server={0}", "comment": "Test case {0} {1} - basic dbimport with ssl", "cmd_opts": " -d {0}".format("./std_data/import_data.sql") }) # ======== mysqlmetagrep =========# tests.append({ "utility": "mysqlmetagrep", "cmd_str": "mysqlmetagrep.py --server={0}", "comment": "Test case {0} {1} - basic metagrep with ssl", "cmd_opts": " -e%{0}".format("mysql") }) # ======== mysqlprocgrep ========= # tests.append({ "utility": "mysqlprocgrep", "cmd_str": "mysqlprocgrep.py --server={0}", "comment": "Test case {0} {1} - basic procgrep with ssl", "cmd_opts": " --match-user={0}".format(self.server1.user) }) # ======== mysqldiskusage ========= # tests.append({ "utility": "mysqldiskusage", "cmd_str": "mysqldiskusage.py --server={0}", "comment": "Test case {0} {1} - basic diskusage with ssl", "cmd_opts": "" }) # ======== mysqlfrm ========= # tests.append({ "utility": "mysqlfrm", "cmd_str": "mysqlfrm.py --server={0}", "comment": "Test case {0} {1} - basic mysqlfrm with ssl", "cmd_opts": " ./ --port={0}".format(self.servers.get_free_port()) }) # ======== mysqldbcopy ========= # tests.append({ "utility": "mysqldbcopy", "cmd_str": "mysqldbcopy.py --source={0} --destination={0}", "comment": "Test case {0} {1} - basic mysqldbcopy with ssl", "cmd_opts": " util_test_a:util_test_z" }) # ======== mysqldiff ========= # tests.append({ "utility": "mysqldiff", "cmd_str": "mysqldiff.py --server1={0} --server2={0}", "comment": "Test case {0} {1} - basic mysqldiff with ssl", "cmd_opts": " util_test_a.t1:util_test_z.t1 --skip-table-options" }) # mysqlbinlogrotate tests.append({ "utility": "mysqlbinlogrotate", "cmd_str": "mysqlbinlogrotate.py --server={0}", "comment": "Test case {0} {1} - basic mysqlbinlogrotate with ssl", "cmd_opts": "" }) # mysqlbinlogpurge tests.append({ "utility": "mysqlbinlogpurge", "cmd_str": "mysqlbinlogpurge.py --server={0}", "comment": "Test case {0} {1} - basic mysqlbinlogpurge with ssl", "cmd_opts": "" }) test_options_group = [] test_options_group.append({ "conn_opts": conn_str, "grp_comment": "Using ssl certificates" }) # Run tests cases using user that requires ssl without ssl # certificates and only --ssl=1 test_options_group.append({ "conn_opts": "{0} --ssl=1".format(conn_str_nossl), "grp_comment": "ssl=1 user require ssl" }) # Run tests cases using user that no requires ssl without ssl # certificates and only --ssl=0 test_options_group.append({ "conn_opts": "{0} --ssl=0".format(conn_ssl_opt), "grp_comment": "ssl=0 user no require ssl" }) # Run tests cases using user that no requires ssl without ssl # certificates and only --ssl=1 Note: server is ssl capable test_options_group.append({ "conn_opts": "{0} --ssl=1".format(conn_ssl_opt), "grp_comment": "ssl=1 user no require ssl" }) test_num = 0 results_list = [] for test_options in test_options_group: for test in tests: grp_cnt = test_options["grp_comment"] test_num += 1 res = self.run_test(test, test_num, test_options["conn_opts"], grp_cnt) if not res: raise MUTLibError( "{0}: failed".format(test['comment'].format(test_num, grp_cnt)) ) else: results_list.append( "{0}: {1}\n" "".format(test["comment"].format(test_num, grp_cnt), "passed") ) self.drop_all() self.load_test_data() self.results = results_list # Mask known source host name. self.replace_result("# Source on ", "# Source on XXXX-XXXX: ... connected.\n") return True
def check_prerequisites(self): # This test requires server version > 5.5.7, due to the lack of # 'GRANT PROXY ON ...' on previews versions. if not self.servers.get_server(0).check_version_compat(5, 5, 8): raise MUTLibError("Test requires server version >= 5.5.8") return self.check_num_servers(1)
def run(self): cmd_str = "mysqlrpladmin.py %s " % self.master_str master_conn = self.build_connection_string(self.server1).strip(' ') slave1_conn = self.build_connection_string(self.server2).strip(' ') slave2_conn = self.build_connection_string(self.server3).strip(' ') slave3_conn = self.build_connection_string(self.server4).strip(' ') slaves_str = ",".join([slave1_conn, slave2_conn, slave3_conn]) comment = "Test case 1 - show health before switchover" cmd_opts = " --slaves=%s --format=vertical health" % slaves_str res = mutlib.System_test.run_test_case(self, 0, cmd_str+cmd_opts, comment) if not res: raise MUTLibError("%s: failed" % comment) # Build connection string with loopback address instead of localhost slave_ports = [self.server2.port, self.server3.port, self.server4.port] slaves_loopback = "root:[email protected]:%s," % self.server2.port slaves_loopback += "root:[email protected]:%s," % self.server3.port slaves_loopback += "root:[email protected]:%s" % self.server4.port slave3_conn_ip = slave3_conn.replace("localhost", "127.0.0.1") # Perform switchover from original master to all other slaves and back. test_cases = [ # (master, [slaves_before], candidate, new_master, [slaves_after]) (master_conn, [slave1_conn, slave2_conn, slave3_conn], slave1_conn, "slave1", [slave2_conn, slave3_conn, master_conn]), (slave1_conn, [slave2_conn, slave3_conn, master_conn], slave2_conn, "slave2", [slave1_conn, slave3_conn, master_conn]), (slave2_conn, [slave1_conn, slave3_conn, master_conn], slave3_conn, "slave3", [slave2_conn, slave1_conn, master_conn]), (slave3_conn_ip, ["root:[email protected]:%s" % self.server3.port, slave1_conn, master_conn], master_conn, "master", [slave1_conn, slave2_conn, slave3_conn]), ] test_num = 2 for case in test_cases: slaves_str = ",".join(case[1]) comment = "Test case %s - switchover to %s" % (test_num, case[3]) cmd_str = "mysqlrpladmin.py --master=%s --rpl-user=rpl:rpl " % case[0] cmd_opts = " --new-master=%s --demote-master " % case[2] cmd_opts += " --slaves=%s switchover" % slaves_str res = mutlib.System_test.run_test_case(self, 0, cmd_str+cmd_opts, comment) if not res: raise MUTLibError("%s: failed" % comment) test_num += 1 slaves_str = ",".join(case[4]) cmd_str = "mysqlrpladmin.py --master=%s " % case[2] comment = "Test case %s - show health after switchover" % test_num cmd_opts = " --slaves=%s --format=vertical health" % slaves_str res = mutlib.System_test.run_test_case(self, 0, cmd_str+cmd_opts, comment) if not res: raise MUTLibError("%s: failed" % comment) test_num += 1 cmd_str = "mysqlrpladmin.py --master=%s " % master_conn cmd_opts = " health --disc=root:root " cmd_opts += "--slaves=%s" % slaves_loopback comment= "Test case %s - health with loopback and discovery" % test_num res = mutlib.System_test.run_test_case(self, 0, cmd_str+cmd_opts, comment) if not res: raise MUTLibError("%s: failed" % comment) test_num += 1 # Perform stop, start, and reset commands = ['stop', 'start', 'stop', 'reset'] for cmd in commands: comment = "Test case %s - run command %s" % (test_num, cmd) cmd_str = "mysqlrpladmin.py --master=%s " % master_conn cmd_opts = " --slaves=%s %s" % (slaves_str, cmd) res = mutlib.System_test.run_test_case(self, 0, cmd_str+cmd_opts, comment) if not res: raise MUTLibError("%s: failed" % comment) test_num += 1 # Now we return the topology to its original state for other tests self.reset_topology() # Mask out non-deterministic data self.do_masks() return True
def run(self): cmd_base = "mysqlrplsync.py" master_con = self.build_connection_string(self.server1).strip(' ') slave1_con = self.build_connection_string(self.server2).strip(' ') slave2_con = self.build_connection_string(self.server3).strip(' ') slave3_con = self.build_connection_string(self.server4).strip(' ') slaves_con = ",".join([slave1_con, slave2_con, slave3_con]) # Show help. test_num = 1 comment = ("Test case {0} - show help." "").format(test_num) cmd = "{0} --help".format(cmd_base) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) if self.debug: print("\nCreate test databases and tables on master.") rpl_sync.create_test_db(self.server1) # Add another database (empty) to be replicated on all slaves and # checked when using the --exclude option. self.server1.exec_query('CREATE DATABASE empty_db') if self.debug: print("\nInsert data into test database on master.") rpl_sync.load_test_data(self.server1) if self.debug: print("\nWait for slaves to catch up with master.") self.wait_for_slaves() # Skip servers with GTID disabled. test_num += 1 comment = ("Test case {0} - skip slave with GTID OFF." "").format(test_num) cmd = "{0} --master={1} --slaves={2}".format(cmd_base, master_con, slaves_con) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) slaves_con = ",".join([slave1_con, slave2_con]) if self.debug: print("\nStop one of the slaves.") self.server2.exec_query('STOP SLAVE') # Skip sync for stopped slaves. test_num += 1 comment = ("Test case {0} - skip sync for stopped slaves." "").format(test_num) cmd = "{0} --master={1} --slaves={2}".format(cmd_base, master_con, slaves_con) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) if self.debug: print("\nCreate a new database on stopped slave and on master.") self.server2.exec_query('CREATE DATABASE `only_on_slave_db`') self.server1.exec_query('SET SQL_LOG_BIN=0') self.server1.exec_query('CREATE DATABASE `only_on_master_db`') self.server1.exec_query('SET SQL_LOG_BIN=1') # Identify missing databases. test_num += 1 comment = ("Test case {0} - identify missing database." "").format(test_num) cmd = "{0} --master={1} --slaves={2}".format(cmd_base, master_con, slaves_con) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) if self.debug: print("\nChange table definition on slave.") self.server2.exec_query('ALTER TABLE `test_rplsync_db`.`t0` ' 'MODIFY rnd_txt0 VARCHAR(50)') # Different table definition. test_num += 1 comment = ("Test case {0} - identify table with different definition." "").format(test_num) cmd = "{0} --master={1} --slaves={2}".format(cmd_base, master_con, slaves_con) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) if self.debug: print("\nRemove tables on master and slave.") last_tbl = '`t{0}`'.format(rpl_sync.TEST_DB_NUM_TABLES - 1) self.server1.exec_query('SET SQL_LOG_BIN=0') self.server1.exec_query('DROP TABLE `test_rplsync_db`.' '{0}'.format(last_tbl)) self.server1.exec_query('SET SQL_LOG_BIN=1') self.server2.exec_query('DROP TABLE `test_rplsync_db`.`t0`') # Identify missing tables. test_num += 1 comment = ("Test case {0} - identify missing tables." "").format(test_num) cmd = "{0} --master={1} --slaves={2}".format(cmd_base, master_con, slaves_con) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) if self.debug: print("\nChanging data on slaves.") self.server2.exec_query("UPDATE `test_rplsync_db`.`t1` " "SET rnd_txt0='changed value' " "WHERE id=1".format(last_tbl)) self.server3.exec_query("INSERT INTO `test_rplsync_db`.`t0` " "(rnd_txt0) VALUES ('new value')") # Identify data difference. test_num += 1 comment = ("Test case {0} - identify data differences on tables." "").format(test_num) cmd = "{0} --master={1} --slaves={2}".format(cmd_base, master_con, slaves_con) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Check a specific database. test_num += 1 comment = ("Test case {0} - check a specific database." "").format(test_num) cmd = ("{0} --master={1} --slaves={2} " "test_rplsync_db").format(cmd_base, master_con, slaves_con) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Exclude check of a specific database. test_num += 1 comment = ("Test case {0} - exclude a specific database." "").format(test_num) cmd = ("{0} --master={1} --slaves={2} " "--exclude=test_rplsync_db").format(cmd_base, master_con, slaves_con) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Check a specific table. test_num += 1 comment = ("Test case {0} - check a specific table." "").format(test_num) cmd = ("{0} --master={1} --slaves={2} " "test_rplsync_db.t0").format(cmd_base, master_con, slaves_con) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Exclude check of a specific table. test_num += 1 comment = ("Test case {0} - exclude a specific table." "").format(test_num) cmd = ("{0} --master={1} --slaves={2} " "--exclude=test_rplsync_db.t0").format(cmd_base, master_con, slaves_con) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Include/exclude data to check (using backtick quotes). test_num += 1 comment = ("Test case {0} - include/exclude data (using backticks)." "").format(test_num) if os.name == 'posix': cmd_arg = ("'`test_rplsync_db`' --exclude='`test_rplsync_db`.`t0`," "`test_rplsync_db`.`t1`'") else: cmd_arg = ('"`test_rplsync_db`" --exclude="`test_rplsync_db`.`t0`,' '`test_rplsync_db`.`t1`"') cmd = ("{0} --master={1} --slaves={2} " "{3}").format(cmd_base, master_con, slaves_con, cmd_arg) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Check a specific database that does not exist. test_num += 1 comment = ("Test case {0} - check a non existing database." "").format(test_num) cmd = ("{0} --master={1} --slaves={2} " "no_exist_db").format(cmd_base, master_con, slaves_con) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Mask out non-deterministic data self.do_masks() return True
server = self.servers.get_server(index) try: res = server.show_server_variable("server_id") except MUTLibError, e: raise MUTLibError("Cannot get replication server " + "server_id: %s" % e.errmsg) else: if self.debug: print "# Cloning server0." serverid = self.servers.get_next_id() if mysqld is None: mysqld = _DEFAULT_MYSQL_OPTS % self.servers.view_next_port() res = self.servers.spawn_new_server(self.server0, serverid, name, mysqld) if not res: raise MUTLibError("Cannot spawn replication server '%s'." & name) self.servers.add_new_server(res[0], True) server = res[0] return server def setup(self): self.res_fname = "result.txt" # Spawn servers self.server0 = self.servers.get_server(0) self.server1 = self.spawn_server("rep_master") self.server2 = self.spawn_server("rep_slave1") self.server3 = self.spawn_server("rep_slave2") self.server4 = self.spawn_server("rep_slave3")
def check_prerequisites(self): if not self.servers.get_server(0).check_version_compat(5, 6, 11): raise MUTLibError("Test requires server version 5.6.11 and later.") self.server0 = None self.server1 = None return self.check_num_servers(1)
def run(self): self.res_fname = "result.txt" from_conn = "--source={0}".format( self.build_connection_string(self.server1)) to_conn = "--destination={0}".format( self.build_connection_string(self.server2)) cmd = "mysqldbcopy.py --skip-gtid {0} {1} ".format(from_conn, to_conn) test_num = 1 comment = ("Test case {0} - copy a sample database X:Y" "").format(test_num) cmd_str = "{0} util_test:util_db_clone".format(cmd) res = self.exec_util(cmd_str, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = "Test case {0} - copy a sample database X".format(test_num) cmd_str = "{0} util_test".format(cmd) res = self.exec_util(cmd_str, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - copy a sample database with blobs " "X:Y".format(test_num)) cmd_str = "{0} blob_test:blob_test_clone".format(cmd) res = self.exec_util(cmd_str, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - copy using different engine" "").format(test_num) cmd_str = ("{0} util_test:util_db_clone --drop-first " "--new-storage-engine=MEMORY").format(cmd) res = self.exec_util(cmd_str, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - copy using " "multiprocessing").format(test_num) cmd_str = "{0} util_test:util_test_multi --multiprocess=2".format(cmd) res = self.exec_util(cmd_str, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - copy blobs using " "multiprocessing").format(test_num) cmd_str = "{0} blob_test:blob_test_multi --multiprocess=2".format(cmd) res = self.exec_util(cmd_str, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - copy a sample database X:Y with weird " "names (backticks)".format(test_num)) # Set input parameter with appropriate quotes for the OS if os.name == 'posix': cmd_arg = "'\"db`:db\":\"db`:db_clone\"'" else: cmd_arg = '"\\"db`:db\\":\\"db`:db_clone\\""' cmd = "mysqldbcopy.py {0} {1} {2}".format(from_conn, to_conn, cmd_arg) res = self.exec_util(cmd, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - copy a sample database X with weird " "names (backticks)".format(test_num)) # Set input parameter with appropriate quotes for the OS if os.name == 'posix': cmd_arg = "'\"db`:db\"'" else: cmd_arg = '"\\"db`:db\\""' cmd = "mysqldbcopy.py {0} {1} {2}".format(from_conn, to_conn, cmd_arg) res = self.exec_util(cmd, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - copy a sample database with views" "".format(test_num)) cmd = "mysqldbcopy.py {0} {1} {2}".format( from_conn, to_conn, "views_test:views_test_clone") res = self.exec_util(cmd, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) # These two DB and tables does not contains any row, and are used # to test DB copy of default character set and collation. # was not move to ./std_data/basic_data.sql to avoid warning # "A partial copy from a server that has GTIDs.." messages # when setup is invoke from subclasses and other tests and # to avoid the creation of an additional file. queries = [ ("CREATE DATABASE util_test_default_collation " "DEFAULT COLLATE utf8_general_ci"), ("CREATE TABLE util_test_default_collation.t1 " "(a char(30)) ENGINE=MEMORY"), ("CREATE DATABASE util_test_default_charset " "DEFAULT CHARACTER SET utf8"), ("CREATE TABLE util_test_default_charset.t1 " "(a char(30)) ENGINE=MEMORY"), 'CREATE DATABASE "util""test" ', ('CREATE TABLE "util""test"."t""1" (' '"id" int(11) NOT NULL AUTO_INCREMENT,' '"name" varchar(100) DEFAULT NULL,' 'PRIMARY KEY ("id")' ') ENGINE=InnoDB DEFAULT CHARSET=latin1'), ('CREATE TABLE "util""test"."t""2" (' '"i""d" int(11) NOT NULL AUTO_INCREMENT,' '"na""me" varchar(100) DEFAULT NULL,' 'PRIMARY KEY ("i""d")' ') ENGINE=InnoDB DEFAULT CHARSET=latin1'), ] for query in queries: self.server1.exec_query(query) test_num += 1 dest_c = "--destination={0}".format( self.build_connection_string(self.server1)) comment = "Test case {0} - copydb default collation".format(test_num) dbs = ("util_test_default_collation:" "util_test_default_collation_copy") cmd = ("mysqldbcopy.py --skip-gtid {0} {1} {2}" "".format(from_conn, dest_c, dbs)) res = self.exec_util(cmd, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = "Test case {0} - copydb default charset".format(test_num) dbs = ("util_test_default_charset:" "util_test_default_charset_copy") cmd = ("mysqldbcopy.py --skip-gtid {0} {1} {2}" "".format(from_conn, dest_c, dbs)) res = self.exec_util(cmd, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 prev_sql_mode = self.server1.select_variable("SQL_MODE") self.server1.exec_query("SET @@SESSION.SQL_MODE=''") try: # Grant ALL on `util_test` for user 'joe'@'localhost' on source self.server1.exec_query("GRANT ALL ON `util_test`.* " "TO 'joe'@'localhost'") # Revoke all privileges to 'joe'@'localhost' in destination self.server2.exec_query("REVOKE ALL PRIVILEGES, GRANT OPTION FROM " "'joe'@'localhost'") # Add all privileges needed for 'joe'@'localhost' in destination db self.server2.exec_query("GRANT SELECT, CREATE, ALTER, INSERT, " "UPDATE, EXECUTE, DROP, LOCK TABLES, " "EVENT, TRIGGER, CREATE ROUTINE, " "REFERENCES, CREATE VIEW ON " "`util_db_privileges`.* TO " "'joe'@'localhost'") # Change DEFINER in procedures and functions on the source server self.server1.exec_query("UPDATE mysql.proc SET " "DEFINER='joe@localhost' WHERE " "DB='util_test'") self.server1.exec_query("UPDATE mysql.event SET " "DEFINER='joe@localhost' WHERE " "DB='util_test'") # Change DEFINER in the views on the source server query = """ SELECT CONCAT("ALTER DEFINER='joe'@'localhost' VIEW ", table_schema, ".", table_name, " AS ", view_definition) FROM information_schema.views WHERE table_schema='util_test' """ res = self.server1.exec_query(query) for row in res: self.server1.exec_query(row[0]) self.server1.exec_query("SET @@SESSION.SQL_MODE={0}" "".format(prev_sql_mode)) # Change DEFINER in the triggers on the source server self.server1.exec_query("DROP TRIGGER util_test.trg") self.server1.exec_query("CREATE DEFINER='joe'@'localhost' " "TRIGGER util_test.trg AFTER INSERT ON " "util_test.t1 FOR EACH ROW INSERT INTO " "util_test.t2 " "VALUES('Test objects count')") except UtilError as err: raise MUTLibError("Failed to execute query: " "{0}".format(err.errmsg)) to_conn = "--destination=joe@localhost:{0}".format(self.server2.port) comment = ("Test case {0} - copy using a user without SUPER privilege" "").format(test_num) cmd = ("mysqldbcopy.py --skip-gtid --skip=grants --drop-first {0} " "{1} util_test:util_db_privileges".format(from_conn, to_conn)) res = self.exec_util(cmd, self.res_fname) self.results.append(res) if res != 0: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 # Change SQL_MODE to 'NO_BACKSLASH_ESCAPES' in the destination server try: previous_sql_mode = self.server2.select_variable("SQL_MODE") self.server2.exec_query("SET @@GLOBAL.SQL_MODE=" "'NO_BACKSLASH_ESCAPES'") except UtilError as err: raise MUTLibError("Failed to change SQL_MODE: " "{0}".format(err.errmsg)) comment = ("Test case {0} - Copy database with blobs and the " "destination server with SQL_MODE='NO_BACKSLASH_ESCAPES'" "").format(test_num) to_conn = "--destination={0}".format( self.build_connection_string(self.server2)) cmd = ("mysqldbcopy.py --skip-gtid {0} {1} {2}".format( from_conn, to_conn, "blob_test:blob_test_no_backslash_escapes")) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Restore previous SQL_MODE in the destination server try: self.server2.exec_query("SET @@GLOBAL.SQL_MODE='{0}'" "".format(previous_sql_mode)) except UtilError as err: raise MUTLibError("Failed to restore SQL_MODE: " "{0}".format(err.errmsg)) # Database and table with single double quotes (") on identifier test_num += 1 comment = "Test case {0} - copydb single double quote".format(test_num) dbs = '\\"util\\"\\"test\\":\\"util\\"\\"test_copy\\"' cmd = ("mysqldbcopy.py --skip-gtid {0} {1} {2} -vv" "".format(from_conn, to_conn, dbs)) res = self.run_test_case(0, cmd, comment) self.results.append(res) if not res: raise MUTLibError("{0}: failed".format(comment)) # Database and table with single double quotes (") on identifier # and destination with SQL_MODE to ''. # Change SQL_MODE to '' in the destination server try: previous_sql_mode = self.server2.select_variable("SQL_MODE") self.server2.exec_query("SET @@GLOBAL.SQL_MODE=" "''") except UtilError as err: raise MUTLibError("Failed to change SQL_MODE: " "{0}".format(err.errmsg)) test_num += 1 comment = ("Test case {0} - copydb single double quote " "and destination server with SQL_MODE set to " "''".format(test_num)) if os.name == 'posix': dbs = "'\"util\"\"test\":`util\"test_no_backslash_escapes`'" else: dbs = '\\"util\\"\\"test\\":`util\\"test_no_backslash_escapes`' cmd = ("mysqldbcopy.py --skip-gtid {0} {1} {2} -vv" "".format(from_conn, to_conn, dbs)) res = self.run_test_case(0, cmd, comment) self.results.append(res) if not res: raise MUTLibError("{0}: failed".format(comment)) # Restore previous SQL_MODE in the destination server try: self.server2.exec_query("SET @@GLOBAL.SQL_MODE='{0}'" "".format(previous_sql_mode)) except UtilError as err: raise MUTLibError("Failed to restore SQL_MODE: " "{0}".format(err.errmsg)) return True
def run(self): self.res_fname = "result.txt" test_num = 1 comment = "Test case {0} - error: no db specified".format(test_num) res = self.run_test_case(2, "mysqlindexcheck.py ", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - error: invalid source " "specified".format(test_num)) res = self.run_test_case(1, "mysqlindexcheck.py util_test " "--server=nope:nada@nohost", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - error: invalid login to " "server".format(test_num)) res = self.run_test_case(1, "mysqlindexcheck.py util_test_a " "--server=nope:nada@localhost:" "{0}".format(self.server1.port), comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - error: stats and " "best=alpha".format(test_num)) res = self.run_test_case(2, "mysqlindexcheck.py --stats --best=A " "util_test_a", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - error: stats and " "worst=alpha".format(test_num)) res = self.run_test_case(2, "mysqlindexcheck.py --stats --worst=A " "util_test_a", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = "Test case {0} - error: not stats ".format(test_num) res = self.run_test_case(2, "mysqlindexcheck.py --best=1 " "util_test_a", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - error: stats and both best and " "worst ".format(test_num)) res = self.run_test_case(2, "mysqlindexcheck.py --stats --best=1 " "--worst=1 util_test_a", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = "Test case {0} - error: stats and worst=-1".format(test_num) res = self.run_test_case(2, "mysqlindexcheck.py --stats --worst=-1 " "util_test_a", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = "Test case {0} - error: stats and best=-1".format(test_num) res = self.run_test_case(2, "mysqlindexcheck.py --stats --best=-1 " "util_test_a", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = "Test case {0} - error: stats and worst=0".format(test_num) res = self.run_test_case(2, "mysqlindexcheck.py --stats --worst=0 " "util_test_a", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = "Test case {0} - error: stats and best=0".format(test_num) res = self.run_test_case(2, "mysqlindexcheck.py --stats --best=0 " "util_test_a", comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.replace_result("ERROR: Can't connect", "ERROR: Can't connect to XXXX\n") self.replace_any_result(["Error 1045", "Error 2003", "Error Can't connect to MySQL server on", "Error Access denied for user"], "Error XXXX: Access denied\n") return True
def setup(self): self.res_fname = "result.txt" self.config_file_path = 'rpl_admin_b_ssl.cnf' # Spawn servers self.server0 = self.servers.get_server(0) mysqld = _DEFAULT_MYSQL_OPTS.format(self.servers.view_next_port()) self.server1 = self.servers.spawn_server( "rep_master_gtid_ssl", mysqld, True ) mysqld = _DEFAULT_MYSQL_OPTS.format(self.servers.view_next_port()) self.server2 = self.servers.spawn_server( "rep_slave1_gtid_ssl", mysqld, True ) mysqld = _DEFAULT_MYSQL_OPTS_DIFF_SSL.format( self.servers.view_next_port() ) self.server3 = self.servers.spawn_server( "rep_slave2_gtid_ssl", mysqld, True ) mysqld = _DEFAULT_MYSQL_OPTS.format(self.servers.view_next_port()) self.server4 = self.servers.spawn_server( "rep_slave3_gtid_ssl", mysqld, True ) self.servers_list = [self.server1, self.server2, self.server3, self.server4] for server in self.servers_list: try: grant_proxy_ssl_privileges(server, ssl_user, ssl_pass) except UtilError as err: raise MUTLibError("{0} on:{1}".format(err.errmsg, server.role)) conn_info = { 'user': ssl_user, 'passwd': ssl_pass, 'host': self.server0.host, 'port': self.server0.port, 'ssl_ca': ssl_c_ca, 'ssl_cert': ssl_c_cert, 'ssl_key': ssl_c_key, } conn_info['port'] = self.server1.port conn_info['port'] = self.server1.port self.server1 = Server.fromServer(self.server1, conn_info) self.server1.connect() conn_info['port'] = self.server2.port conn_info['port'] = self.server2.port self.server2 = Server.fromServer(self.server2, conn_info) self.server2.connect() conn_info['port'] = self.server3.port conn_info['port'] = self.server3.port conn_info['ssl_ca'] = ssl_c_ca_b conn_info['ssl_cert'] = ssl_c_cert_b conn_info['ssl_key'] = ssl_c_key_b self.server3 = Server.fromServer(self.server3, conn_info) self.server3.connect() conn_info['port'] = self.server4.port conn_info['port'] = self.server4.port conn_info['ssl_ca'] = ssl_c_ca conn_info['ssl_cert'] = ssl_c_cert conn_info['ssl_key'] = ssl_c_key self.server4 = Server.fromServer(self.server4, conn_info) self.server4.connect() server_n = 0 for server in [self.server1, self.server2, self.server3, self.server4]: server_n += 1 res = server.exec_query("SHOW STATUS LIKE 'Ssl_cipher'") if not res[0][1]: raise MUTLibError("Cannot spawn the SSL server{0}." "".format(server_n)) # Reset spawned servers (clear binary log and GTID_EXECUTED set) self.reset_master() # Update server list self.servers_list = [self.server1, self.server2, self.server3, self.server4] # setup config_path config_p = ConfigParser.ConfigParser() self.test_server_names = [] with open(self.config_file_path, 'w') as config_f: for server in self.servers_list: group_name = 'server_{0}'.format(server.port) self.test_server_names.append(group_name) config_p.add_section(group_name) config_p.set(group_name, 'user', server.user) config_p.set(group_name, 'password', server.passwd) config_p.set(group_name, 'host', server.host) config_p.set(group_name, 'port', server.port) config_p.set(group_name, 'ssl-ca', server.ssl_ca) config_p.set(group_name, 'ssl-cert', server.ssl_cert) config_p.set(group_name, 'ssl-key', server.ssl_key) config_p.write(config_f) master = self.servers_list[0] slaves_list = self.servers_list[1:] # Used for port masking. self.m_port = self.server1.port self.s1_port = self.server2.port self.s2_port = self.server3.port self.s3_port = self.server4.port return self.reset_topology(slaves_list, master=master)
def run(self): test_num = 1 master_conn = self.build_connection_string(self.server1).strip(' ') slave1_conn = self.build_connection_string(self.server2).strip(' ') slave2_conn = self.build_connection_string(self.server3).strip(' ') slave3_conn = self.build_connection_string(self.server4).strip(' ') comment = ("Test case {0} - mysqlrplshow OLD Master " "before demote".format(test_num)) cmd_str = "mysqlrplshow.py --master={0} ".format(master_conn) cmd_opts = "--discover-slaves={0} ".format(master_conn.split('@')[0]) res = self.run_test_case(0, cmd_str + cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - loopback ([::1]) " "switchover demote-master ".format(test_num)) cmd_str = "mysqlrpladmin.py --master={0} ".format(master_conn) cmd_opts = (" --new-master={0} --discover-slaves={1} " "--rpl-user=rpluser:hispassword --demote-master " "switchover".format(slave1_conn, master_conn.split('@')[0])) res = self.run_test_case(0, cmd_str + cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") test_num += 1 comment = ("Test case {0} - mysqlrplshow " "NEW Master after demote".format(test_num)) cmd_str = "mysqlrplshow.py --master={0} ".format(slave1_conn) cmd_opts = "--discover-slaves={0} ".format(master_conn.split('@')[0]) res = self.run_test_case(0, cmd_str + cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - mysqlrplcheck " "NEW Master after demote".format(test_num)) cmd_str = "mysqlrplcheck.py --master={0} ".format(slave1_conn) cmd_opts = "--slave={0} ".format(master_conn) res = self.run_test_case(0, cmd_str + cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") test_num += 1 comment = ("Test case {0} - loopback " "([::1]) failover ".format(test_num)) cmd_str = "mysqlrpladmin.py " slaves = ",".join([slave2_conn, slave3_conn, master_conn]) cmd_opts = (" --slaves={0} --rpl-user=rpluser:hispassword " "failover".format(slaves)) res = self.run_test_case(0, cmd_str + cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") test_num += 1 comment = ("Test case {0} - mysqlrplshow " "NEW Master after failover".format(test_num)) cmd_str = "mysqlrplshow.py --master={0} ".format(slave2_conn) cmd_opts = "--discover-slaves={0} ".format(master_conn.split('@')[0]) res = self.run_test_case(0, cmd_str + cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Mask out non-deterministic data rpl_admin.test.do_masks(self) self.replace_result("# QUERY = SELECT " "WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(", "# QUERY = SELECT " "WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS(XXXXX)\n") self.remove_result_and_lines_before("WARNING: There are slaves that" " had connection errors.") self.replace_result("| 127.0.0.1 | PORT2 | MASTER | UP " "| ON | OK | ", "| 127.0.0.1 | PORT2 | MASTER | UP " "| ON | OK | XXXXXXXX " "| XXXXXXXX | XXXXXXXX " "| | | " "| | | " "| | " "| |\n") self.replace_result("| 127.0.0.1 | PORT1 | SLAVE | UP " "| ON | OK | ", "| 127.0.0.1 | PORT1 | SLAVE | UP " "| ON | OK | XXXXXXXX " "| XXXXXXXX | XXXXXXXX " "| Yes | Yes | 0 " "| No | 0 | " "| 0 | " "| 0 |\n") self.replace_result("| 127.0.0.1 | PORT3 | SLAVE | UP " "| ON | OK | ", "| 127.0.0.1 | PORT3 | SLAVE | UP " "| ON | OK | XXXXXXXX " "| XXXXXXXX | XXXXXXXX " "| Yes | Yes | 0 " "| No | 0 | " "| 0 | " "| 0 |\n") self.replace_result("| 127.0.0.1 | PORT4 | SLAVE | UP " "| ON | OK | ", "| 127.0.0.1 | PORT4 | SLAVE | UP " "| ON | OK | XXXXXXXX " "| XXXXXXXX | XXXXXXXX " "| Yes | Yes | 0 " "| No | 0 | " "| 0 | " "| 0 |\n") self.replace_result("| 127.0.0.1 | PORT1 | MASTER | UP " "| ON | OK | ", "| 127.0.0.1 | PORT1 | MASTER | UP " "| ON | OK | XXXXXXXX " "| XXXXXXXX | XXXXXXXX " "| | | " "| | | " "| | " "| |\n") self.mask_column_result("| version", "|", 2, " XXXXXXXX ") self.mask_column_result("| master_log_file", "|", 2, " XXXXXXXX ") self.mask_column_result("| master_log_pos", "|", 2, " XXXXXXXX ") # Mask slaves behind master. # It happens sometimes on windows in a non-deterministic way. self.replace_substring("+---------------------------------------------" "------------------------------------------+", "+---------+") self.replace_substring("+---------------------------------------------" "-------------------------------------------+", "+---------+") self.replace_substring("| health " " |", "| health |") self.replace_substring("| health " " |", "| health |") self.replace_substring("| OK " " |", "| OK |") self.replace_substring("| OK " " |", "| OK |") self.replace_substring_portion("| Slave delay is ", "transactions behind master. |", "| OK |") self.replace_substring("| Slave has 1 transactions behind master. " " |", "| OK |") self.replace_substring("| Slave has 1 transactions behind master. " " |", "| OK |") self.replace_substring("+------------------------------------------+", "+---------+") self.replace_substring("| health |", "| health |") self.replace_substring("| OK |", "| OK |") self.replace_substring("| Slave has 1 transactions behind master. |", "| OK |") return True
def run(self): config_file = self.config_file_path master = '{0}[server_{1}]'.format(config_file, self.server1.port) slave1 = '{0}[server_{1}]'.format(config_file, self.server2.port) slave2 = '{0}[server_{1}]'.format(config_file, self.server3.port) slave3 = '{0}[server_{1}]'.format(config_file, self.server4.port) test_num = 1 comment = ("Test case {0} - SSL " "switchover demote-master ".format(test_num)) cmd_str = "mysqlrpladmin.py --master={0} ".format(master) slaves = [slave1, slave2, slave3] cmd_opts = (" --new-master={0} " "--rpl-user=rpluser:hispassword --demote-master " "switchover --slaves={1}" "").format(slave1, ",".join(slaves)) cmds = "{0} {1}".format(cmd_str, cmd_opts) res = self.run_test_case(0, cmds, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") test_num += 1 comment = ("Test case {0} - SSL mysqlrplcheck " "NEW Master after demote".format(test_num)) cmd_opts = "--slave={0} --show-slave-status".format(master) cmd_str = "mysqlrplcheck.py --master={0} ".format(slave1) cmds = "{0} {1}".format(cmd_str, cmd_opts) res = self.run_test_case(0, cmds, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") test_num += 1 comment = ("Test case {0} - SSL mysqlrplcheck " "NEW Master after demote".format(test_num)) cmd_opts = "--slave={0} --show-slave-status".format(slave2) cmds = "{0} {1}".format(cmd_str, cmd_opts) res = self.run_test_case(0, cmds, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") test_num += 1 comment = ("Test case {0} - SSL mysqlrplcheck " "NEW Master after demote".format(test_num)) cmd_opts = "--slave={0} --show-slave-status".format(slave3) cmds = "{0} {1}".format(cmd_str, cmd_opts) res = self.run_test_case(0, cmds, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") test_num += 1 comment = ("Test case {0} - SSL " "failover ".format(test_num)) cmd_str = "mysqlrpladmin.py --master={0}".format(slave1) slaves = ",".join([slave2, slave3, master]) cmd_opts = (" --slaves={0} --rpl-user=rpluser:hispassword " "failover".format(slaves)) cmd_opts = "{0} --candidates={1}".format(cmd_opts, slaves) cmds = "{0} {1}".format(cmd_str, cmd_opts) res = self.run_test_case(0, cmds, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") test_num += 1 comment = ("Test case {0} - SSL mysqlrplcheck " "NEW Master after demote".format(test_num)) cmd_str = "mysqlrplcheck.py --master={0} ".format(slave2) cmd_opts = "--slave={0} --show-slave-status".format(master) cmds = "{0} {1}".format(cmd_str, cmd_opts) res = self.run_test_case(0, cmds, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") test_num += 1 comment = ("Test case {0} - SSL mysqlrplcheck " "NEW Master after demote".format(test_num)) cmd_opts = "--slave={0} --show-slave-status".format(slave3) cmds = "{0} {1}".format(cmd_str, cmd_opts) res = self.run_test_case(0, cmds, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("\n") self.mask_results() return True
def run(self): from_conn = "--server={0}".format( self.build_connection_string(self.server1)) # TODO : make a test for '--skip-rpl' # Copy master database test_num = 1 db_list = ["master_db1"] to_conn = "--server={0}".format( self.build_connection_string(self.server2)) for exp_fmt in _FORMATS: cmd_list = [] comment = ("Test case {0} - Copy extra database from master to " "slave - format =".format(test_num)) exp_cmd = _EXPORT_CMD.format(exp_fmt, "master", " ".join(db_list), from_conn, "", _RPL_FILE) cmd_list.append(exp_cmd) imp_str = _IMPORT_CMD.format(to_conn, _RPL_FILE, exp_fmt, "") cmd_list.append(imp_str) res = self.run_test_case(0, test_num, self.server1, self.server1, self.server2, cmd_list, db_list, "", comment + exp_fmt, _TEST_CASE_RESULTS, True) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 # Provision a new slave from master to_conn = "--server={0}".format( self.build_connection_string(self.server3)) db_list = ["util_test", "master_db1"] cmd_list = [] exp_cmd = _EXPORT_CMD.format("sql", "master", " ".join(db_list), from_conn, "", _RPL_FILE) cmd_list.append(exp_cmd) imp_str = _IMPORT_CMD.format(to_conn, _RPL_FILE, "sql", "") cmd_list.append(imp_str) comment = ("Test case {0} - Provision a new slave from the " "master".format(test_num)) res = self.run_test_case(0, test_num, self.server1, self.server1, self.server3, cmd_list, db_list, "", comment + " sql", _TEST_CASE_RESULTS, True) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 # Provision a new slave from existing slave from_conn = "--server={0}".format( self.build_connection_string(self.server2)) cmd_list = [] exp_cmd = _EXPORT_CMD.format("sql", "slave", " ".join(db_list), from_conn, "", _RPL_FILE) cmd_list.append(exp_cmd) imp_str = _IMPORT_CMD.format(to_conn, _RPL_FILE, "sql", "") cmd_list.append(imp_str) comment = ("Test case {0} - Provision a new slave from existing " "slave".format(test_num)) res = self.run_test_case(0, test_num, self.server1, self.server2, self.server3, cmd_list, db_list, "", comment + " sql", _TEST_CASE_RESULTS, True) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 # Now show the --skip-rpl effects # New rows will not appear in row count because the CM and START # commands are skipped. self.server3.exec_query("STOP SLAVE") self.server3.exec_query("DROP DATABASE util_test") self.server3.exec_query("DROP DATABASE master_db1") cmd_list = [] exp_cmd = _EXPORT_CMD.format("sql", "slave", " ".join(db_list), from_conn, "", _RPL_FILE) cmd_list.append(exp_cmd) imp_str = _IMPORT_CMD.format(to_conn, _RPL_FILE, "sql", " --skip-rpl ") cmd_list.append(imp_str) comment = "Test case {0} - Use --skip-rpl on import".format(test_num) res = self.run_test_case(0, test_num, self.server1, self.server2, self.server3, cmd_list, db_list, "", comment + " sql", _TEST_CASE_RESULTS, False, True) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 # Rollback here to avoid active transaction error for STOP SLAVE with # 5.5 servers. if self.servers.get_server(0).check_version_compat(5, 5, 0): self.server3.rollback() # Do the last test case again but don't skip to show rows are updated self.server3.exec_query("STOP SLAVE") self.server3.exec_query("RESET SLAVE") self.server3.exec_query("DROP DATABASE util_test") self.server3.exec_query("DROP DATABASE master_db1") cmd_list = [] exp_cmd = _EXPORT_CMD.format("sql", "slave", " ".join(db_list), from_conn, "", _RPL_FILE) cmd_list.append(exp_cmd) imp_str = _IMPORT_CMD.format(to_conn, _RPL_FILE, "sql", " --skip-rpl ") cmd_list.append(imp_str) comment = "Test case {0} - Use --skip-rpl on import".format(test_num) res = self.run_test_case(0, test_num, self.server1, self.server2, self.server3, cmd_list, db_list, "", comment + " sql", _TEST_CASE_RESULTS, True) if not res: raise MUTLibError("{0}: failed".format(comment)) return True
def run(self): self.mask_global = False # Turn off global masks self.res_fname = "result.txt" s1_conn = "--server1={0}".format( self.build_connection_string(self.server1)) s2_conn = "--server2={0}".format( self.build_connection_string(self.server2)) s2_conn_dupe = "--server2={0}".format( self.build_connection_string(self.server1)) cmd_base = "mysqldiff.py {0} {1} ".format(s1_conn, s2_conn) test_num = 1 comment = "Test case {0} - diff a sample database".format(test_num) cmd = "{0} util_test:util_test".format(cmd_base) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - diff a single object - not " "same".format(test_num)) cmd = "{0} util_test.t2:util_test.t2".format(cmd_base) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - diff a single object - is " "same".format(test_num)) cmd = "{0} util_test.t3:util_test.t3".format(cmd_base) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - diff multiple objects - are " "same".format(test_num)) cmd = ("{0} util_test.t3:util_test.t3 " "util_test.t4:util_test.t4".format(cmd_base)) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - diff multiple objects + database - some " "same".format(test_num)) cmd = ("{0} util_test.t3:util_test.t3 util_test.t4:util_test.t4 " "util_test:util_test --force".format(cmd_base)) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # execute a diff on the same server to test messages self.server1.exec_query("CREATE DATABASE util_test1") test_num += 1 comment = ("Test case {0} - diff two databases on same server " "w/server2".format(test_num)) cmd = ("mysqldiff.py {0} {1} " "util_test:util_test1".format(s1_conn, s2_conn_dupe)) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - diff two databases on same " "server".format(test_num)) cmd = "mysqldiff.py {0} util_test:util_test1".format(s1_conn) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - diff a sample database with weird names " "(backticks)".format(test_num)) # Set input parameter with appropriate quotes for the OS if os.name == 'posix': cmd_arg = "'\"db.`:db\":\"db.`:db\"'" else: cmd_arg = '"\\"db.`:db\\":\\"db.`:db\\""' cmd = "mysqldiff.py {0} {1} {2}".format(s1_conn, s2_conn, cmd_arg) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - diff a single object with weird names " "(backticks)".format(test_num)) # Set input parameter with appropriate quotes for the OS if os.name == 'posix': cmd_arg = ("'\"db.`:db\".\"`t`.`export_2\":" "\"db.`:db\".\"`t`.`export_2\"'") else: cmd_arg = ('"\\"db.`:db\\".\\"`t`.`export_2\\":' '\\"db.`:db\\".\\"`t`.`export_2\\""') cmd = "mysqldiff.py {0} {1} {2}".format(s1_conn, s2_conn, cmd_arg) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - diff a sample database containing tables " "with weird names (no backticks) and different table " "options.".format(test_num)) cmd_arg = "db_diff_test:db_diff_test" cmd = "mysqldiff.py {0} {1} {2}".format(s1_conn, s2_conn, cmd_arg) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - diff a sample database containing tables " "with weird names (no backticks) and skipping " "table options.".format(test_num)) cmd_arg = "db_diff_test:db_diff_test --skip-table-options" cmd = "mysqldiff.py {0} {1} {2}".format(s1_conn, s2_conn, cmd_arg) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Diff databases with objects of different type with the same name # Create the same PROCEDURE on each server with the same name of an # already existing TABLE (i.e., ```t``export_1`). self.server1.exec_query( "CREATE PROCEDURE `db.``:db`.```t``export_1`() " "SELECT 1") self.server2.exec_query( "CREATE PROCEDURE `db.``:db`.```t``export_1`() " "SELECT 1") if os.name == 'posix': cmd_arg = "'\"db.`:db\":\"db.`:db\"'" else: cmd_arg = '"\\"db.`:db\\":\\"db.`:db\\""' # Execute test (no differences expected) test_num += 1 comment = ("Test case {0} - diff a database with objects of " "different types with the same name " "(no differences)".format(test_num)) cmd = "mysqldiff.py {0} {1} {2}".format(s1_conn, s2_conn, cmd_arg) res = self.run_test_case(0, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Replace the PROCEDURE previously created on one of the servers by a # different one. self.server2.exec_query("DROP PROCEDURE `db.``:db`.```t``export_1`") self.server2.exec_query( "CREATE PROCEDURE `db.``:db`.```t``export_1`() " "SELECT 2") # Execute test (differences expected) test_num += 1 comment = ("Test case {0} - diff a database with objects of " "different types with the same name " "(with differences)".format(test_num)) cmd = "mysqldiff.py {0} {1} {2}".format(s1_conn, s2_conn, cmd_arg) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Set input parameter with appropriate quotes for the OS if os.name == 'posix': cmd_arg = ("'\"db.`:db\".\"`t`export_1\":" "\"db.`:db\".\"`t`export_1\"'") else: cmd_arg = ('"\\"db.`:db\\".\\"`t`export_1\\":' '\\"db.`:db\\".\\"`t`export_1\\""') # Execute test for specific objects (differences expected) test_num += 1 comment = ("Test case {0} - diff specific objects of " "different types with the same name " "(with differences)".format(test_num)) cmd = "mysqldiff.py {0} {1} {2}".format(s1_conn, s2_conn, cmd_arg) res = self.run_test_case(1, cmd, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # The following are necessary due to changes in character spaces # introduced with Python 2.7.X in the difflib. self.replace_result("+++ util_test.t1", "+++ util_test.t1\n") self.replace_result("+++ util_test.t2", "+++ util_test.t2\n") self.replace_result("--- util_test.t1", "--- util_test.t1\n") self.replace_result("--- util_test.t2", "--- util_test.t2\n") self.replace_substring("on [::1]", "on localhost") return True
def run(self): self.res_fname = "result.txt" from_conn = "--server={0}".format( self.build_connection_string(self.server1)) cmd_str = ("mysqldbexport.py --skip=events,grants --no-headers {0} " "--format=CSV util_test --skip-gtid".format(from_conn)) test_num = 1 comment = "Test case {0} - exclude by name.".format(test_num) cmd_opts = ("{0} --exclude=util_test.v1 " "--exclude=util_test.t4".format(cmd_str)) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - exclude by name using " "backticks.".format(test_num)) if os.name == 'posix': cmd_opts = ("{0} --exclude='`util_test`.`v1`' " "--exclude='`util_test`.`t4`'".format(cmd_str)) else: cmd_opts = ('{0} --exclude="`util_test`.`v1`" ' '--exclude="`util_test`.`t4`"'.format(cmd_str)) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - exclude using SQL LIKE " "pattern.".format(test_num)) cmd_opts = "{0} -x f% -x _4".format(cmd_str) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - exclude using REGEXP " "pattern.".format(test_num)) cmd_opts = "{0} -x ^f -x 4$ --regexp".format(cmd_str) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - exclude by name and SQL LIKE " "pattern.".format(test_num)) cmd_opts = ("{0} --exclude=f% --exclude=_4 -x p% --exclude=v1 " "--exclude=util_test.trg".format(cmd_str)) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - exclude by name and REGEXP " "pattern.".format(test_num)) cmd_opts = ("{0} --exclude=^f --exclude=4$ -x ^p --exclude=v1 " "--exclude=util_test.trg --regexp".format(cmd_str)) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - exclude everything using SQL LIKE " "pattern.".format(test_num)) cmd_opts = "{0} -x % ".format(cmd_str) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - exclude everything using REGEXP " "pattern.".format(test_num)) if os.name == 'posix': cmd_opts = "{0} -x '.*' --regexp".format(cmd_str) else: cmd_opts = '{0} -x ".*" --regexp'.format(cmd_str) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Note: Unlike SQL LIKE pattern that matches the entire value, with a # SQL REGEXP pattern match succeeds if the pattern matches anywhere in # the value being tested. # See: http://dev.mysql.com/doc/en/pattern-matching.html test_num += 1 comment = ("Test case {0}a - SQL LIKE VS REGEXP pattern (match entire " "value VS match anywhere in value).".format(test_num)) cmd_opts = "{0} -x 1 -x t".format(cmd_str) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) comment = ("Test case {0}b - SQL LIKE VS REGEXP pattern (match entire " "value VS match anywhere in value).".format(test_num)) cmd_opts = "{0} -x 1 -x t --regexp".format(cmd_str) res = self.run_test_case(0, cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) export_parameters_def.test._mask_csv(self) ## Mask known source. self.replace_result("# Source on localhost: ... connected.", "# Source on XXXX-XXXX: ... connected.\n") self.replace_result("# Source on [::1]: ... connected.", "# Source on XXXX-XXXX: ... connected.\n") # Mask GTID warning when servers with GTID enabled are used self.remove_result("# WARNING: The server supports GTIDs but you") return True
def run(self): self.res_fname = "result.txt" master_conn = self.build_connection_string(self.server1).strip(' ') slave1_conn = self.build_connection_string(self.server2).strip(' ') slave2_conn = self.build_connection_string(self.server3).strip(' ') slave3_conn = self.build_connection_string(self.server4).strip(' ') master_str = "--master={0}".format(master_conn) slaves_str = "--slaves={0}".format(",".join( [slave1_conn, slave2_conn, slave3_conn])) candidates_str = "--candidates={0}".format(",".join( [slave1_conn, slave2_conn, slave3_conn])) test_num = 1 comment = ("Test case {0} - warning for --exec* and not switchover or " "failover".format(test_num)) cmd_str = ("mysqlrpladmin.py {0} {1} health --quiet --format=csv " " --exec-before=dummy " "--exec-after=dummy".format(master_str, slaves_str)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - warning for --candidate and not " "switchover".format(test_num)) cmd_str = ("mysqlrpladmin.py {0} {1} health --quiet --format=csv " "{2}".format(master_str, slaves_str, candidates_str)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - warning for --new-master and not " "switchover".format(test_num)) cmd_str = ("mysqlrpladmin.py {0} {1} health --quiet --format=tab " " --new-master={2} ".format(master_str, slaves_str, slave2_conn)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - warning for missing " "--report-host".format(test_num)) cmd_str = ("mysqlrpladmin.py {0} --disco=root:root health " "--format=csv ".format(master_str)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - warning for missing " "--report-host (using --verbose)".format(test_num)) cmd_str = ("mysqlrpladmin.py {0} --disco=root:root health " "--format=csv --verbose".format(master_str)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 comment = ("Test case {0} - warning for --format and not health or " "gtid".format(test_num)) cmd_str = ("mysqlrpladmin.py {0} {1} stop --quiet " "--format=tab ".format(master_str, slaves_str)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Reset the topology to its original state self.reset_topology( [self.server2, self.server3, self.server4, self.server5]) test_num += 1 comment = ("Test case {0} - warning for --master and " "failover".format(test_num)) cmd_str = ("mysqlrpladmin.py {0} {1} " "failover".format(master_str, slaves_str)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Reset the topology to its original state self.reset_topology( [self.server2, self.server3, self.server4, self.server5]) test_num += 1 comment = ("Test case {0} - warnings for switchover with offline " "slave".format(test_num)) off_slaves_str = ",".join( [slave2_conn, slave3_conn, "root@offline:1234"]) cmd_str = ("mysqlrpladmin.py --master={0} --new-master={1} --slaves=" "{2} switchover ".format(master_conn, slave1_conn, off_slaves_str)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Reset the topology, using a slave with GTID_MODE=OFF self.reset_topology([ self.server2, self.server3, self.server4, self.server5, self.server7 ]) test_num += 1 comment = ("Test case {0} - elect using a slave with " "gtid disabled.".format(test_num)) slave4_conn = self.build_connection_string(self.server7).strip(' ') slaves_str = ",".join( [slave1_conn, slave2_conn, slave3_conn, slave4_conn]) cmd_str = ("mysqlrpladmin.py --master={0} --slaves={1} " "elect".format(master_conn, slaves_str)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Reset the topology, using a master with GTID_MODE=OFF self.reset_topology( [self.server2, self.server3, self.server4, self.server5], master=self.server6) test_num += 1 comment = ("Test case {0} - elect using a master with " "gtid disabled.".format(test_num)) master2_conn = self.build_connection_string(self.server6).strip(' ') slaves_str = ",".join([slave1_conn, slave2_conn, slave3_conn]) cmd_str = ("mysqlrpladmin.py --master={0} --slaves={1} " "elect".format(master2_conn, slaves_str)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Reset the topology to its original state for other tests self.reset_topology( [self.server2, self.server3, self.server4, self.server5]) # Mask out non-deterministic data rpl_admin.test.do_masks(self) # Mask server port. self.replace_substring(str(self.server5.port), "PORT5") # Mask slaves behind master. # It happens sometimes on windows in a non-deterministic way. self.replace_substring( "+--------------------------------------------" "--+", "+---------------------------+") self.replace_substring( "| health " " |", "| health |") self.replace_substring( "| OK " " |", "| OK |") self.replace_substring( "| Slave delay is 1 seconds behind master., " "No |", "| OK |") self.replace_substring( "| Cannot connect to slave. " " |", "| Cannot connect to slave. |") # Mask verbose health report. self.replace_result("localhost,PORT1,MASTER,UP,ON,OK,", "localhost,PORT1,MASTER,UP,ON,OK, ...\n") self.replace_result("localhost,PORT2,SLAVE,UP,ON,OK,", "localhost,PORT2,SLAVE,UP,ON,OK, ...\n") self.replace_result("localhost,PORT3,SLAVE,UP,ON,OK,", "localhost,PORT3,SLAVE,UP,ON,OK, ...\n") self.replace_result("localhost,PORT4,SLAVE,UP,ON,OK,", "localhost,PORT4,SLAVE,UP,ON,OK, ...\n") return True
try: self.servers.spawn_new_servers(num_servers) except MUTLibError, e: raise MUTLibError("Cannot spawn needed servers: %s" % \ e.errmsg) else: num_servers -= 1 # Get last server in list self.server0 = self.servers.get_server(0) index = self.servers.find_server_by_name("import_basic") if index >= 0: self.server1 = self.servers.get_server(index) try: res = self.server1.show_server_variable("server_id") except MUTLibError, e: raise MUTLibError("Cannot get import_basic server " + "server_id: %s" % e.errmsg) self.s1_serverid = int(res[0][1]) else: self.s1_serverid = self.servers.get_next_id() res = self.servers.spawn_new_server(self.server0, self.s1_serverid, "import_basic") if not res: raise MUTLibError("Cannot spawn import_basic server.") self.server1 = res[0] self.servers.add_new_server(self.server1, True) try: self.server1.exec_query("SET GLOBAL default_storage_engine=MEMORY") except: self.server1.exec_query("SET GLOBAL storage_engine=MEMORY") return True
def run(self): self.res_fname = "result.txt" base_cmd = "mysqlrpladmin.py " master_conn = self.build_connection_string(self.server1).strip(' ') slave1_conn = self.build_connection_string(self.server2).strip(' ') slave2_conn = self.build_connection_string(self.server3).strip(' ') slave3_conn = self.build_connection_string(self.server4).strip(' ') master_str = "--master=" + master_conn # create a user for priv check self.server1.exec_query("CREATE USER 'joe'@'localhost'") self.server1.exec_query( "GRANT SELECT, SUPER ON *.* TO 'jane'@'localhost'") mock_master1 = "--master=joe@localhost:%s" % self.server1.port mock_master2 = "--master=jane@localhost:%s" % self.server1.port slaves_str = "--slaves=" + \ ",".join([slave1_conn, slave2_conn, slave3_conn]) candidates_str = "--candidates=" + \ ",".join([slave1_conn, slave2_conn, slave3_conn]) # List of test cases for test test_cases = [ # (comment, ret_val, option1, ...), ("Multiple commands issued.", 2, "switchover", "start"), ("No commands.", 2, ""), ("Invalid command.", 2, "NOTACOMMAND"), ("Switchover but no --master, --new-master,", 2, "switchover"), ("No slaves or discover-slaves-login", 2, "switchover", master_str), ("Force used with failover", 2, "failover", "--force", master_str, slaves_str), ("Bad --new-master connection string", 2, "switchover", master_str, slaves_str, "--new-master=whatmeworry?"), ("Bad --master connection string", 1, "switchover", slaves_str, "--new-master=%s" % master_conn, "--master=whatmeworry?"), ("Bad --slaves connection string", 1, "switchover", master_str, "--new-master=%s" % master_conn, "--slaves=what,me,worry?"), ("Bad --candidates connection string", 1, "failover", master_str, slaves_str, "--candidates=what,me,worry?"), ("Not enough privileges - health joe", 1, "health", mock_master1, slaves_str), ("Not enough privileges - health jane", 0, "health", mock_master2, slaves_str), ("Not enough privileges - switchover jane", 1, "switchover", mock_master2, slaves_str, "--new-master=%s" % slave3_conn), ] test_num = 1 for case in test_cases: comment = "Test case %s - %s" % (test_num, case[0]) parts = [base_cmd] for opt in case[2:]: parts.append(opt) cmd_str = " ".join(parts) res = mutlib.System_test.run_test_case(self, case[1], cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) test_num += 1 # Now test to see what happens when master is listed as a slave comment = "Test case %s - Master listed as a slave - literal" % test_num cmd_str = "%s health %s %s,%s" % (base_cmd, master_str, slaves_str, master_conn) res = mutlib.System_test.run_test_case(self, 2, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) test_num += 1 comment = "Test case %s - Master listed as a slave - alias" % test_num cmd_str = "%s health %s %s" % (base_cmd, master_str, "--slaves=root:root@%s:%s" % \ (socket.gethostname().split('.', 1)[0], self.server1.port)) res = mutlib.System_test.run_test_case(self, 2, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) test_num += 1 comment = "Test case %s - Master listed as a candiate - alias" % test_num cmd_str = "%s elect %s %s %s" % (base_cmd, master_str, "--candidates=root:root@%s:%s" % \ (socket.gethostname().split('.', 1)[0], self.server1.port), slaves_str) res = mutlib.System_test.run_test_case(self, 2, cmd_str, comment) if not res: raise MUTLibError("%s: failed" % comment) test_num += 1 # Now we return the topology to its original state for other tests rpl_admin.test.reset_topology(self) # Mask out non-deterministic data rpl_admin.test.do_masks(self) self.replace_result( "mysqlrpladmin.py: error: New master connection " "values invalid", "mysqlrpladmin.py: error: New master connection " "values invalid\n") self.replace_result( "ERROR: Master connection values invalid or " "cannot be parsed", "ERROR: Master connection values invalid or " "cannot be parsed\n") self.replace_result( "ERROR: Slave connection values invalid or " "cannot be parsed", "ERROR: Slave connection values invalid or " "cannot be parsed\n") self.replace_result( "ERROR: Candidate connection values invalid or " "cannot be parsed", "ERROR: Candidate connection values invalid or " "cannot be parsed\n") return True
def check_prerequisites(self): if not self.servers.get_server(0).check_version_compat(5, 6, 5): raise MUTLibError("Test requires server version prior to 5.6.5") return self.check_num_servers(1)
def run(self): self.res_fname = "result.txt" from_conn = "--server={0}".format( self.build_connection_string(self.server1)) conn_val = self.get_connection_values(self.server2) self.server2_conn = "-u{0} -p{1} --host=localhost ".format( conn_val[0], conn_val[1]) if conn_val[3] is not None: self.server2_conn = "{0}--port={1} ".format( self.server2_conn, conn_val[3]) cmd = "mysqldbexport.py {0} util_test --skip-gtid ".format(from_conn) test_num = 1 comment = ("Test case {0} - export metadata to new server via the " "mysql monitor".format(test_num)) cmd_str = cmd + (" --export=definitions --format=SQL --quiet " "--skip=events,grants | " "{0} {1} --protocol=tcp".format( self.mysql_path, self.server2_conn)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("{0}\n".format( self.check_objects(self.server2, "util_test", False))) test_num += 1 comment = ("Test case {0} - export the data to " "new server via the mysql monitor".format(test_num)) cmd_str = cmd + (" --export=data --format=SQL --quiet " "--skip=events,grants | " "{0} {1} --protocol=tcp".format( self.mysql_path, self.server2_conn)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.show_data("t1") self.show_data("t2") self.show_data("t3") self.show_data("t4") try: self.server2.exec_query("DROP DATABASE util_test") except UtilError: raise MUTLibError("Cannot drop database before import.") self.results.append("{0}\n".format( self.check_objects(self.server2, "util_test", False))) test_num += 1 comment = ("Test case {0} - export all objects and data to new server " "via the mysql monitor".format(test_num)) cmd_str = cmd + (" --export=both --format=SQL --quiet " "--skip=events,grants | " "{0} {1} --protocol=tcp".format( self.mysql_path, self.server2_conn)) res = self.run_test_case(0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) self.results.append("{0}\n".format( self.check_objects(self.server2, "util_test", False))) self.show_data("t1") self.show_data("t2") self.show_data("t3") self.show_data("t4") self.remove_result("Warning: Using a password on the") # mysql client might also issue a warning if a password is used on the # command line. self.remove_result("mysql: [Warning] Using a password on the command " "line interface can be insecure.") return True
def exec_export_import(self, server1, server2, exp_cmd, imp_cmd, test_num, test_case, ret_val=True, reset=True, load_data=True): """Execute export import. server1[in] Server instance. server2[in] Server instance. exp_cmd[in] Export command. imp_cmd[in] Import command. test_num[in] Test number. test_case[in] Test case. ret_val[in] Return value. reset[in] True for reset. load_data[in] True for load data. """ conn1 = "--server={0}".format(self.build_connection_string(server1)) conn2 = "--server={0}".format(self.build_connection_string(server2)) if load_data: try: server1.read_and_exec_SQL(self.data_file, self.debug) except UtilError as err: raise MUTLibError("Failed to read commands from file {0}: " "{1}".format(self.data_file, err.errmsg)) comment = "Test case {0} (export phase) {1}".format(test_num, test_case) cmd_str = "{0}{1} > {2}".format(exp_cmd, conn1, self.export_file) res = mutlib.System_test.run_test_case(self, 0, cmd_str, comment) if not res: # Output additional information if the executed command fails # in order to help determine the issue. print("Test output (results):") for row in self.results: print row, print("Command failing: {0}".format(cmd_str)) print("Export file {0}:".format(self.export_file)) with open(self.export_file.strip()) as f: for row in f: print row, raise MUTLibError("{0}: failed".format(comment)) # Display the export file if in debug mode if self.debug: with open(self.export_file.strip()) as f: for row in f: print row, comment = "Test case {0} (import phase) {1}".format(test_num, test_case) if reset: server2.exec_query("RESET MASTER") # reset GTID_EXECUTED cmd_str = "{0}{1} {2}".format(imp_cmd, conn2, self.export_file) res = mutlib.System_test.run_test_case(self, 0, cmd_str, comment) if res != ret_val: # Output additional information if the executed command fails # in order to help determine the issue. print("Test output (results):") for row in self.results: print row, print("Command failing: {0}".format(cmd_str)) print("Export file {0}:".format(self.export_file)) with open(self.export_file.strip()) as f: for row in f: print row, raise MUTLibError("{0}: failed".format(comment)) self.drop_all()
def run(self): test_num = 1 self.server2.exec_query(_SET_SQL_LOG_BIN.format('0')) self.server2.exec_query(_CREATE_USER) self.server2.exec_query(_GRANT_QUERY) self.server2.exec_query(_SET_SQL_LOG_BIN.format('1')) self.server3.exec_query(_SET_SQL_LOG_BIN.format('0')) self.server3.exec_query(_CREATE_USER) self.server3.exec_query(_GRANT_QUERY) self.server3.exec_query(_SET_SQL_LOG_BIN.format('1')) self.server4.exec_query(_SET_SQL_LOG_BIN.format('0')) self.server4.exec_query(_CREATE_USER) self.server4.exec_query(_GRANT_QUERY) self.server4.exec_query(_SET_SQL_LOG_BIN.format('1')) self.server5.exec_query(_SET_SQL_LOG_BIN.format('0')) self.server5.exec_query(_CREATE_USER) self.server5.exec_query(_GRANT_QUERY) self.server5.exec_query(_SET_SQL_LOG_BIN.format('1')) # create a database then add data shutting down slaves to create # a scenario where the candidate slave has fewer transactions than # the slaves to execute the relay log execution logic and the # check for transactions to skip connecting candidate to slaves as # its master self.server1.exec_query("CREATE DATABASE test_relay") self.server1.exec_query("CREATE TABLE test_relay.t1" "(a int, b char(20)) ENGINE=INNODB") self.server1.exec_query("INSERT INTO test_relay.t1 VALUES (1, 'one')") self.wait_for_slave(self.server1, self.server2) self.wait_for_slave(self.server1, self.server3) # Stop the candidate and one other slave self.server2.exec_query("STOP SLAVE") self.server3.exec_query("STOP SLAVE") self.server1.exec_query("INSERT INTO test_relay.t1 VALUES (2, 'two')") self.wait_for_slave(self.server1, self.server4) # Stop the third slave self.server4.exec_query("STOP SLAVE SQL_THREAD") self.server1.exec_query("INSERT INTO test_relay.t1 " "VALUES (3, 'three')") self.server1.exec_query("INSERT INTO test_relay.t1 " "VALUES (4, 'four')") self.wait_for_slave(self.server1, self.server5) # Show contents of server for server in self.servers_list: self.dump_table(server) comment = ("Test case {0} - failover to {1}:{2} with relay log " "entries".format(test_num, self.server2.host, self.server2.port)) slaves = ",".join([self.slave2_conn, self.slave3_conn, self.slave4_conn]) cmd_str = "mysqlrpladmin.py --master={0} ".format(self.master_conn) cmd_opts = (" --candidates={0} --slaves={1} failover -vvv " "--force".format(self.slave1_conn, slaves)) res = mutlib.System_test.run_test_case(self, 0, cmd_str + cmd_opts, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) test_num += 1 # Wait for slaves for slave in [self.server3, self.server4, self.server5]: self.wait_for_slave(self.server2, slave) # Show contents of server for server in self.servers_list: # ROLLBACK just to close any pending transaction, otherwise # dump_table() can return inconsistent values. server.rollback() self.dump_table(server) comment = ("Test case {0} - failover to {1}:{2} with skipping " "slaves".format(test_num, self.server3.host, self.server3.port)) slaves = ",".join([self.slave3_conn, self.slave4_conn]) cmd_str = ("mysqlrpladmin.py --master={0} --candidates={1} " "--slaves={2} failover -vvv" "".format(self.slave1_conn, self.slave2_conn, slaves)) res = mutlib.System_test.run_test_case(self, 0, cmd_str, comment) if not res: raise MUTLibError("{0}: failed".format(comment)) # Now we return the topology to its original state for other tests rpl_admin.test.reset_topology(self) # Mask out non-deterministic data rpl_admin.test.do_masks(self) self.replace_substring(str(self.s4_port), "PORT5") # Strip health report - not needed. self.remove_result("+-") self.remove_result("| ") # Strip GTID detailed information self.replace_result("# QUERY = SELECT WAIT_UNTIL_SQL_THREAD_AFTER", "# QUERY = SELECT WAIT_UNTIL_SQL_THREAD_AFTER" "_GTIDS(XXXXXXXXX)\n") self.replace_result("# Return Code", "# Return Code = XXXX\n") return True
def setup(self): self.server0 = self.servers.get_server(0) self.server1 = None self.server2 = None self.server3 = None index = self.servers.find_server_by_name("with_gtids_1") if index >= 0: self.server1 = self.servers.get_server(index) try: res = self.server1.show_server_variable("server_id") except UtilError as err: raise MUTLibError("Cannot get gtid enabled server 1 " "server_id: {0}".format(err.errmsg)) self.s1_serverid = int(res[0][1]) else: self.s1_serverid = self.servers.get_next_id() res = self.servers.spawn_new_server( self.server0, self.s1_serverid, "with_gtids_1", _DEFAULT_MYSQL_OPTS) if not res: raise MUTLibError("Cannot spawn gtid enabled server 1.") self.server1 = res[0] self.servers.add_new_server(self.server1, True) index = self.servers.find_server_by_name("with_gtids_2") if index >= 0: self.server2 = self.servers.get_server(index) try: res = self.server2.show_server_variable("server_id") except UtilError as err: raise MUTLibError("Cannot get gtid enabled server 2 " "server_id: {0}".format(err.errmsg)) self.s2_serverid = int(res[0][1]) else: self.s2_serverid = self.servers.get_next_id() res = self.servers.spawn_new_server( self.server0, self.s2_serverid, "with_gtids_2", _DEFAULT_MYSQL_OPTS) if not res: raise MUTLibError("Cannot spawn gtid enabled server 2.") self.server2 = res[0] self.servers.add_new_server(self.server2, True) index = self.servers.find_server_by_name("no_gtids") if index >= 0: self.server3 = self.servers.get_server(index) try: res = self.server3.show_server_variable("server_id") except UtilError as err: raise MUTLibError("Cannot get non-gtid server server_id: " "{0}".format(err.errmsg)) self.s3_serverid = int(res[0][1]) else: self.s3_serverid = self.servers.get_next_id() res = self.servers.spawn_new_server(self.server0, self.s3_serverid, "no_gtids", '"--log-bin=mysql-bin "') if not res: raise MUTLibError("Cannot spawn non-gtid server.") self.server3 = res[0] self.servers.add_new_server(self.server3, True) return True
def test_rplms_daemon(self, cmd, logfile, comment, pidfile, stop_daemon): """Test multi-source replication daemon. cmd[in] Command to be executed. logfile[in] Log filename. comment[in] Test comment. pidfile[in] PID file. stop_daemon[in] True to execute --daemon=stop This method create a process by executing the command and waits for the round-robin scheduling to switch all the masters. At the end compares the databases. """ # Since this test case expects the process to stop, we can launch it # via a subprocess and wait for it to finish. if self.debug: print(comment) print("# COMMAND: {0}".format(cmd)) # Run command proc, _ = self.start_process(cmd) # Wait for process to load if self.debug: print("# Waiting for daemon to start.") i = 1 time.sleep(1) while proc.poll() is not None: time.sleep(1) i += 1 if i > _TIMEOUT: if self.debug: print("# Timeout daemon to start.") raise MUTLibError("{0}: failed - timeout waiting for " "daemon to start.".format(comment)) # Since we don't have any control over the process, try to # read the PID to ensure that process started. try: with open(pidfile, "r") as f: int(f.read().strip()) break # The daemon is running except IOError: continue except SystemExit: continue except ValueError: continue # Wait for logfile file to be created if self.debug: print("# Waiting for logfile to be created.") for i in range(_TIMEOUT): if os.path.exists(logfile): break else: time.sleep(1) else: raise MUTLibError("{0}: failed - timeout waiting for " "logfile '{1}' to be " "created.".format(comment, logfile)) # Test if pidfile was created with the correct umask if oct(stat.S_IMODE(os.stat(pidfile).st_mode)) != "0640": raise MUTLibError("{0}: failed - the pidfile was not created with " "the correct umask.".format(comment)) # Wait for switching all the masters self.wait_for_switching_all_masters(logfile, comment) # Compare databases self.compare_databases(comment) if stop_daemon: # Stop daemon if self.debug: print("# Waiting for daemon to end.") # Build stop command by replacing (re)start for stop cmd_stop = re.sub("--daemon=(re)?start", "--daemon=stop", cmd) self.start_process(cmd_stop) i = 0 while True: time.sleep(1) i += 1 if i > _TIMEOUT: if self.debug: print("# Timeout daemon to stop.") raise MUTLibError("{0}: failed - timeout waiting for " "daemon to stop.".format(comment)) if not os.path.exists(pidfile): break phrase = "Multi-source replication daemon stopped" if self.debug: print("# Waiting for multi-source replication daemon to stop.") i = 0 with open(logfile, "r") as file_: while i < _TIMEOUT: line = file_.readline() if not line: i += 1 time.sleep(1) elif phrase in line: break else: if self.debug: print("# Timeout waiting for multi-source replication " "daemon to stop.") raise MUTLibError("{0}: failed - timeout waiting for " "multi-source daemon to stop." "".format(comment)) # Cleanup after test case try: os.unlink(logfile) except OSError: pass