forked from sysown/proxysql
-
Notifications
You must be signed in to change notification settings - Fork 0
/
proxysql_base_test.py
210 lines (171 loc) · 7.5 KB
/
proxysql_base_test.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
import os
import os.path
import subprocess
import time
from unittest import TestCase
from docker import Client
from docker.utils import kwargs_from_env
import MySQLdb
from docker_fleet import DockerFleet
from proxysql_ping_thread import ProxySQL_Ping_Thread
from proxysql_tests_config import ProxySQL_Tests_Config
class ProxySQLBaseTest(TestCase):
SCENARIO = None
# TODO(andrei): make it possible to turn this to True as well
INTERACTIVE_TEST = False
# Custom, per-test, config overrides
CONFIG_OVERRIDES = {}
def setUp(self):
self.docker_fleet = DockerFleet(config_overrides=ProxySQLBaseTest.CONFIG_OVERRIDES)
# TODO(aismail): revive interactive mode
#if cls.INTERACTIVE_TEST:
# cls._compile_host_proxysql()
# cls._connect_gdb_to_proxysql_within_container()
#self._start_proxysql_pings()
def tearDown(self):
# TODO(aismail): revive interactive mode
#if cls.INTERACTIVE_TEST:
# cls._gdb_process.wait()
# It's essential that pings are stopped __after__ the gdb process has
# finished. This allows them to keep pinging ProxySQL in the background
# while it's stuck waiting for user interaction (user interaction needed
# in order to debug the problem causing it to crash).
#self._stop_proxysql_pings()
pass
def run_sysbench_proxysql(self, threads=4, time=60, db="test",
username=None, password=None, port=None):
"""Runs a sysbench test with the given parameters against the given
ProxySQL instance.
In this case, due to better encapsulation and reduced latency to
ProxySQL, we are assuming that sysbench is installed on the same
container with it.
"""
config = ProxySQL_Tests_Config(overrides=ProxySQLBaseTest.CONFIG_OVERRIDES)
hostname = config.get('ProxySQL', 'hostname')
username = username or config.get('ProxySQL', 'username')
password = password or config.get('ProxySQL', 'password')
port = port or config.get('ProxySQL', 'port')
params = [
"sysbench",
"--test=/opt/sysbench/sysbench/tests/db/oltp.lua",
"--num-threads=%d" % threads,
"--max-requests=0",
"--max-time=%d" % time,
"--mysql-user=%s" % username,
"--mysql-password=%s" % password,
"--mysql-db=%s" % db,
"--db-driver=mysql",
"--oltp-tables-count=4",
"--oltp-read-only=on",
"--oltp-skip-trx=on",
"--report-interval=1",
"--oltp-point-selects=100",
"--oltp-table-size=400000",
"--mysql-host=%s" % hostname,
"--mysql-port=%s" % port
]
self.run_bash_command_within_proxysql(params + ["prepare"])
self.run_bash_command_within_proxysql(params + ["run"])
self.run_bash_command_within_proxysql(params + ["cleanup"])
def run_bash_command_within_proxysql(self, params):
"""Run a bash command given as an array of tokens within the ProxySQL
container.
This is useful in a lot of scenarios:
- running sysbench against the ProxySQL instance
- getting environment variables from the ProxySQL container
- running various debugging commands against the ProxySQL instance
"""
proxysql_container_id = self.docker_fleet.get_proxysql_container()
exec_params = ["docker", "exec", proxysql_container_id] + params
subprocess.call(exec_params)
def _compile_host_proxysql(self):
"""Compile ProxySQL on the Docker host from which we're running the
tests.
This is used for remote debugging, because that's how the
gdb + gdbserver pair works:
- local gdb with access to the binary with debug symbols
- remote gdbserver which wraps the remote binary so that it can be
debugged when it crashes.
"""
subprocess.call(["make", "clean"])
subprocess.call(["make"])
def _connect_gdb_to_proxysql_within_container(self):
"""Connect a local gdb running on the docker host to the remote
ProxySQL binary for remote debugging.
This is useful in interactive mode, where we want to stop at a failing
test and prompt the developer to debug the failing instance.
Note: gdb is ran in a separate process because otherwise it will block
the test running process, and it will not be able to run queries anymore
and make assertions. However, we save the process handle so that we can
shut down the process later on.
"""
self._gdb_process = subprocess.Popen(["gdb", "--command=gdb-commands.txt",
"./proxysql"],
cwd="./src")
def _start_proxysql_pings(self):
"""During the running of the tests, the test suite will continuously
monitor the ProxySQL daemon in order to check that it's up.
This special thread will do exactly that."""
config = ProxySQL_Tests_Config(overrides=ProxySQLBaseTest.CONFIG_OVERRIDES)
self.ping_thread = ProxySQL_Ping_Thread(config)
self.ping_thread.start()
def _stop_proxysql_pings(self):
"""Stop the special thread which pings the ProxySQL daemon."""
self.ping_thread.stop()
self.ping_thread.join()
def run_query_proxysql(self, query, db,
hostname=None, port=None,
username=None, password=None,
return_result=True):
return self.docker_fleet.run_query_proxysql(query, db,
hostname, port,
username, password,
return_result)
def run_query_proxysql_admin(self, query, return_result=True):
return self.docker_fleet.run_query_proxysql_admin(query, return_result)
def run_query_mysql(self, query, db, return_result=True, hostgroup=0,
username=None, password=None):
return self.docker_fleet.run_query_mysql(query, db, return_result,
hostgroup,
username, password)
def run_query_mysql_container(self, query, db, container_id, return_result=True):
return self.docker_fleet.run_query_mysql_container(query=query,
db=db,
container_id=container_id,
return_result=return_result)
def get_proxysql_container(self):
return self.docker_fleet.get_proxysql_container()
def get_mysql_containers(self, hostgroup=0):
return self.docker_fleet.get_mysql_containers(hostgroup=hostgroup)
def get_environment_variables_from_container(self, container_id):
return self.docker_fleet.get_environment_variables_from_container(container_id)
def get_tests_config(self):
return ProxySQL_Tests_Config(overrides=ProxySQLBaseTest.CONFIG_OVERRIDES)
def docker_inspect(self, container_id):
return self.docker_fleet.docker_inspect(container_id)
def run_in_docker_scenarios(self, f, scenarios=[], proxysql_filters={}, mysql_filters={}):
"""Runs a function in a number of docker scenarios.
This is a helper for running your test assertions against different
configurations without having to go the extra mile.
"""
print('##################### Running test %r' % f)
scenarios = self.docker_fleet.generate_scenarios(scenarios=scenarios,
proxysql_filters=proxysql_filters,
mysql_filters=mysql_filters)
committed_images = set()
copy_folder = True
delete_folder = True
for (i, scenario) in enumerate(scenarios):
print("******** Running scenario %s (proxysql_image=%s, mysql_image=%s)" %
(scenario['scenario_dir'], scenario['proxysql_image'], scenario['mysql_image']))
copy_folder = (i == 0)
delete_folder = (i == len(scenarios) - 1)
folder = self.docker_fleet.start_temp_scenario(scenario, copy_folder)
f()
if scenario['proxysql_image'] not in committed_images:
self.docker_fleet.commit_proxysql_image(scenario['proxysql_image'])
committed_images.add(scenario['proxysql_image'])
if scenario['mysql_image'] not in committed_images:
self.docker_fleet.commit_proxysql_image(scenario['mysql_image'])
committed_images.add(scenario['mysql_image'])
self.docker_fleet.stop_temp_scenario(folder, delete_folder)