| # Copyright (C) 2018 The Android Open Source Project |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| import os.path |
| import re |
| import time |
| |
| import pytest |
| |
| MYSQL_HOST = "k8sgerrit-mysql" |
| MYSQL_PORT = 3306 |
| MYSQL_ROOT_PASSWORD = "big_secret" |
| REPL_PASSWORD = "test" |
| |
| @pytest.fixture() |
| def mock_dump(): |
| return ("CREATE DATABASE `users`;" |
| "USE `users`;" |
| "CREATE TABLE `users` (" |
| "`id` INT(11) NOT NULL," |
| "`first_name` VARCHAR(50)," |
| "`last_name` VARCHAR(50)," |
| "`password` VARCHAR(100)," |
| "PRIMARY KEY (`id`))") |
| |
| @pytest.fixture(scope="module") |
| def mock_sql_script(tmp_path_factory): |
| tmp_dir = tmp_path_factory.mktemp("mysql_init_script") |
| with open(os.path.join(tmp_dir, "initialize-slave.sql"), "w") as sql_file: |
| sql_file.write(( |
| "USE `users`;" |
| "SET @query = CONCAT(" |
| "\"INSERT INTO `users` (id, first_name, last_name, password) \"," |
| "\"VALUES (1, 'John', 'Doe', '\", @replpwd, \"');\");" |
| "PREPARE stmt FROM @query;" |
| "EXECUTE stmt;")) |
| return tmp_dir |
| |
| @pytest.fixture(scope="module") |
| def mysql_container(request, docker_client, docker_network, mysql_container_factory): |
| mysql_container = mysql_container_factory( |
| docker_client, docker_network, MYSQL_HOST, MYSQL_PORT, MYSQL_ROOT_PASSWORD) |
| |
| request.addfinalizer(mysql_container.stop_mysql_container) |
| |
| return mysql_container |
| |
| @pytest.fixture(scope="module") |
| def init_container(request, docker_client, docker_network, |
| mysql_replication_init_image, mock_sql_script): |
| container_run = docker_client.containers.run( |
| image=mysql_replication_init_image.id, |
| environment={ |
| "MYSQL_HOST": MYSQL_HOST, |
| "MYSQL_PORT": MYSQL_PORT, |
| "MYSQL_ROOT_PASSWORD": MYSQL_ROOT_PASSWORD, |
| "REPL_PASSWORD": REPL_PASSWORD |
| }, |
| volumes={ |
| mock_sql_script: { |
| "bind": "/var/sql", |
| "mode": "ro" |
| } |
| }, |
| network=docker_network.name, |
| name="mysql-replication-init", |
| detach=True |
| ) |
| |
| def stop_container(): |
| container_run.stop(timeout=1) |
| container_run.remove(v=True, force=True) |
| |
| request.addfinalizer(stop_container) |
| |
| return container_run |
| |
| @pytest.fixture(scope="module") |
| def containers(mysql_container, init_container): |
| return mysql_container, init_container |
| |
| @pytest.mark.slow |
| @pytest.mark.incremental |
| class TestMysqlInitScript(object): |
| def test_mysql_replication_init_waiting_for_dump(self, containers): |
| (_, init_container) = containers |
| timeout = time.time() + 20 |
| while time.time() < timeout: |
| last_log_line = init_container.logs(tail=1).decode("utf-8").strip() |
| if last_log_line == \ |
| "Waiting for database dump file at /var/data/db/master_dump.sql": |
| break |
| assert timeout > time.time() |
| |
| def test_mysql_replication_init_accepts_dump(self, containers, mock_dump): |
| (_, init_container) = containers |
| cmd = "/bin/bash -c \"echo '%s' > /var/data/db/master_dump.sql\"" % mock_dump |
| init_container.exec_run(cmd) |
| timeout = time.time() + 20 |
| while time.time() < timeout: |
| logs = init_container.logs().decode("utf-8") |
| if re.search(r"Database dump received", logs): |
| break |
| assert timeout > time.time() |
| |
| def test_mysql_replication_init_finishes(self, containers): |
| (_, init_container) = containers |
| timeout = time.time() + 20 |
| while time.time() < timeout: |
| init_container.reload() |
| if init_container.status == "exited": |
| break |
| assert timeout > time.time() |
| assert init_container.attrs["State"]["ExitCode"] == 0 |
| |
| def test_mysql_replication_init_applies_dump(self, containers): |
| (mysql_container, _) = containers |
| connection = mysql_container.connect() |
| result = connection.execute("SHOW DATABASES;") |
| connection.close() |
| assert "users" in [row[0] for row in result] |
| |
| def test_mysql_replication_init_runs_slave_init_script(self, containers): |
| (mysql_container, _) = containers |
| connection = mysql_container.connect() |
| result = connection.execute("USE `users`;") |
| result = connection.execute("SELECT password FROM users WHERE id=1 LIMIT 1;") |
| connection.close() |
| for row in result: |
| assert REPL_PASSWORD in row["password"] |