]> git.ipfire.org Git - thirdparty/pdns.git/blame - regression-tests.api/runtests.py
Merge pull request #12100 from rgacogne/ddist-single-soa-ixfr
[thirdparty/pdns.git] / regression-tests.api / runtests.py
CommitLineData
1a152698
CH
1#!/usr/bin/env python
2#
3# Shell-script style.
4
541bb91b 5from __future__ import print_function
1a152698 6import os
a1e51a8a 7import requests
2e8f4675 8from requests.exceptions import HTTPError
02945d9a 9import shutil
1a152698
CH
10import subprocess
11import sys
12import tempfile
a1e51a8a 13import time
1a152698 14
7a0ea291 15try:
16 raw_input
17except NameError:
18 raw_input = input
19
0bbd0a64
KM
20MYSQL_DB='pdnsapi'
21MYSQL_USER='root'
22MYSQL_HOST=os.environ.get('MYSQL_HOST', 'localhost')
23MYSQL_PASSWD=''
24
25PGSQL_DB='pdnsapi'
0bbd0a64 26
1a152698 27SQLITE_DB = 'pdns.sqlite3'
0bbd0a64
KM
28
29LMDB_DB = 'pdns.lmdb'
30
7992c698
CH
31WEBPORT = 5556
32DNSPORT = 5300
bbef8f04 33APIKEY = '1234567890abcdefghijklmnopq-key'
c563cbe5 34WEBPASSWORD = 'something'
c6c3c165 35PDNSUTIL_CMD = [os.environ.get("PDNSUTIL", "../pdns/pdnsutil"), "--config-dir=."]
1a152698 36
0bbd0a64
KM
37ZONES = ["example.com", "powerdnssec.org", "cryptokeys.org"]
38ZONE_DIR = "../regression-tests/zones/"
39
40AUTH_MYSQL_TPL = """
41# Generated by runtests.py
42launch=gmysql
43gmysql-dnssec=on
44gmysql-dbname="""+MYSQL_DB+"""
45gmysql-user="""+MYSQL_USER+"""
46gmysql-host="""+MYSQL_HOST+"""
47gmysql-password="""+MYSQL_PASSWD+"""
48"""
49
50AUTH_PGSQL_TPL = """
1a152698 51# Generated by runtests.py
0bbd0a64
KM
52launch=gpgsql
53gpgsql-dnssec=on
54gpgsql-dbname="""+PGSQL_DB+"""
bc6f4e68
KM
55# on conflict is available in pg 9.5 and up
56gpgsql-set-tsig-key-query=insert into tsigkeys (name,algorithm,secret) values($1,$2,$3) on conflict(name, algorithm) do update set secret=Excluded.secret
ccfabd0d
CH
57"""
58
0bbd0a64 59AUTH_SQLITE_TPL = """
ccfabd0d 60# Generated by runtests.py
0bbd0a64 61launch=gsqlite3
ccfabd0d
CH
62gsqlite3-dnssec=on
63gsqlite3-database="""+SQLITE_DB+"""
0bbd0a64
KM
64"""
65
66AUTH_LMDB_TPL = """
67# Generated by runtests.py
68launch=lmdb
69lmdb-filename="""+LMDB_DB+"""
70"""
71
72AUTH_COMMON_TPL = """
ccfabd0d 73module-dir=../regression-tests/modules
1258fecd 74default-soa-edit=INCEPTION-INCREMENT
0bbd0a64
KM
75launch+=bind
76bind-config=bindbackend.conf
ef550199 77loglevel=5
a21e8566
CH
78"""
79
80BINDBACKEND_CONF_TPL = """
81# Generated by runtests.py
1a152698
CH
82"""
83
41942bb3
CH
84ACL_LIST_TPL = """
85# Generated by runtests.py
86# local host
87127.0.0.1
88::1
89"""
90
35189b7d
KF
91ACL_NOTIFY_LIST_TPL = """
92# Generated by runtests.py
93# local host
94127.0.0.1
95::1
96"""
97
02945d9a
CH
98REC_EXAMPLE_COM_CONF_TPL = """
99# Generated by runtests.py
57a954ff 100auth-zones+=example.com=../regression-tests/zones/example.com.rec
02945d9a
CH
101"""
102
103REC_CONF_TPL = """
104# Generated by runtests.py
105auth-zones=
106forward-zones=
107forward-zones-recurse=
2c4e6880 108allow-from-file=acl.list
35189b7d 109allow-notify-from-file=acl-notify.list
d07bf7ff 110api-config-dir=%(conf_dir)s
02945d9a 111include-dir=%(conf_dir)s
6ab8d5ea 112devonly-regression-test-mode
02945d9a
CH
113"""
114
c1374bdb 115
02945d9a
CH
116def ensure_empty_dir(name):
117 if os.path.exists(name):
118 shutil.rmtree(name)
119 os.mkdir(name)
120
121
7992c698
CH
122def format_call_args(cmd):
123 return "$ '%s'" % ("' '".join(cmd))
124
125
126def run_check_call(cmd, *args, **kwargs):
541bb91b 127 print(format_call_args(cmd))
7992c698
CH
128 subprocess.check_call(cmd, *args, **kwargs)
129
130
5f8fa6d4
CH
131wait = ('--wait' in sys.argv)
132if wait:
133 sys.argv.remove('--wait')
134
6754ef71
CH
135tests = [opt for opt in sys.argv if opt.startswith('--tests=')]
136if tests:
137 for opt in tests:
138 sys.argv.remove(opt)
139tests = [opt.split('=', 1)[1] for opt in tests]
140
0bbd0a64
KM
141daemon = (len(sys.argv) >= 2) and sys.argv[1] or None
142backend = (len(sys.argv) == 3) and sys.argv[2] or 'gsqlite3'
143
144if daemon not in ('authoritative', 'recursor') or backend not in ('gmysql', 'gpgsql', 'gsqlite3', 'lmdb'):
145 print("Usage: ./runtests (authoritative|recursor) [gmysql|gpgsql|gsqlite3|lmdb]")
7c876c30
CH
146 sys.exit(2)
147
148daemon = sys.argv[1]
149
7992c698 150pdns_server = os.environ.get("PDNSSERVER", "../pdns/pdns_server")
bf6096f5 151pdns_recursor = os.environ.get("PDNSRECURSOR", "../pdns/recursordist/pdns_recursor")
7992c698
CH
152common_args = [
153 "--daemon=no", "--socket-dir=.", "--config-dir=.",
154 "--local-address=127.0.0.1", "--local-port="+str(DNSPORT),
c563cbe5
CH
155 "--webserver=yes", "--webserver-port="+str(WEBPORT), "--webserver-address=127.0.0.1",
156 "--webserver-password="+WEBPASSWORD,
7992c698
CH
157 "--api-key="+APIKEY
158]
bf6096f5 159
0567c609
CH
160# Take sdig if it exists (recursor in travis), otherwise build it from Authoritative source.
161sdig = os.environ.get("SDIG", "")
162if sdig:
163 sdig = os.path.abspath(sdig)
164if not sdig or not os.path.exists(sdig):
165 run_check_call(["make", "-C", "../pdns", "sdig"])
166 sdig = "../pdns/sdig"
167
118d3b31 168
7c876c30 169if daemon == 'authoritative':
c6c3c165 170 zone2sql = os.environ.get("ZONE2SQL", "../pdns/zone2sql")
7c876c30 171
0bbd0a64
KM
172 # Prepare mysql DB with some zones.
173 if backend == 'gmysql':
174 subprocess.call(["mysqladmin", "--user=" + MYSQL_USER, "--password=" + MYSQL_PASSWD, "--host=" + MYSQL_HOST, "--force", "drop", MYSQL_DB])
175
176 run_check_call(["mysqladmin", "--user=" + MYSQL_USER, "--password=" + MYSQL_PASSWD, "--host=" + MYSQL_HOST, "create", MYSQL_DB])
177
178 with open('../modules/gmysqlbackend/schema.mysql.sql', 'r') as schema_file:
179 run_check_call(["mysql", "--user=" + MYSQL_USER, "--password=" + MYSQL_PASSWD, "--host=" + MYSQL_HOST, MYSQL_DB], stdin=schema_file)
180
181 with open('pdns.conf', 'w') as pdns_conf:
182 pdns_conf.write(AUTH_MYSQL_TPL + AUTH_COMMON_TPL)
183
184 # Prepare pgsql DB with some zones.
185 elif backend == 'gpgsql':
5a8b492c 186 subprocess.call(["dropdb", PGSQL_DB])
0bbd0a64 187
5a8b492c 188 subprocess.check_call(["createdb", PGSQL_DB])
0bbd0a64
KM
189
190 with open('../modules/gpgsqlbackend/schema.pgsql.sql', 'r') as schema_file:
5a8b492c 191 subprocess.check_call(["psql", PGSQL_DB], stdin=schema_file)
0bbd0a64
KM
192
193 with open('pdns.conf', 'w') as pdns_conf:
194 pdns_conf.write(AUTH_PGSQL_TPL + AUTH_COMMON_TPL)
195
ccfabd0d 196 # Prepare sqlite DB with some zones.
0bbd0a64
KM
197 elif backend == 'gsqlite3':
198 subprocess.call("rm -f " + SQLITE_DB + "*", shell=True)
199
200 with open('../modules/gsqlite3backend/schema.sqlite3.sql', 'r') as schema_file:
201 run_check_call(["sqlite3", SQLITE_DB], stdin=schema_file)
202
203 with open('pdns.conf', 'w') as pdns_conf:
204 pdns_conf.write(AUTH_SQLITE_TPL + AUTH_COMMON_TPL)
205
206 # Prepare lmdb DB with some zones.
207 elif backend == 'lmdb':
208 subprocess.call("rm -f " + LMDB_DB + "*", shell=True)
209
210 with open('pdns.conf', 'w') as pdns_conf:
211 pdns_conf.write(AUTH_LMDB_TPL + AUTH_COMMON_TPL)
7c876c30 212
a21e8566
CH
213 with open('bindbackend.conf', 'w') as bindbackend_conf:
214 bindbackend_conf.write(BINDBACKEND_CONF_TPL)
215
0bbd0a64
KM
216 for zone in ZONES:
217 run_check_call(PDNSUTIL_CMD + ["load-zone", zone, ZONE_DIR+zone])
ccfabd0d 218
7992c698 219 run_check_call(PDNSUTIL_CMD + ["secure-zone", "powerdnssec.org"])
f5ad09dc 220 servercmd = [pdns_server] + common_args + ["--no-shuffle", "--dnsupdate=yes", "--cache-ttl=0", "--api=yes"]
7c876c30
CH
221
222else:
02945d9a
CH
223 conf_dir = 'rec-conf.d'
224 ensure_empty_dir(conf_dir)
41942bb3
CH
225 with open('acl.list', 'w') as acl_list:
226 acl_list.write(ACL_LIST_TPL)
35189b7d
KF
227 with open('acl-notify.list', 'w') as acl_notify_list:
228 acl_notify_list.write(ACL_NOTIFY_LIST_TPL)
02945d9a
CH
229 with open('recursor.conf', 'w') as recursor_conf:
230 recursor_conf.write(REC_CONF_TPL % locals())
231 with open(conf_dir+'/example.com..conf', 'w') as conf_file:
232 conf_file.write(REC_EXAMPLE_COM_CONF_TPL)
7c876c30 233
2c4e6880 234 servercmd = [pdns_recursor] + common_args
1a152698
CH
235
236
237# Now run pdns and the tests.
541bb91b
CH
238print("Launching server...")
239print(format_call_args(servercmd))
ab6031a1 240serverproc = subprocess.Popen(servercmd, close_fds=True, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
1a152698 241
541bb91b 242print("Waiting for webserver port to become available...")
a1e51a8a 243available = False
ab6031a1 244time.sleep(1)
a1e51a8a
CH
245for try_number in range(0, 10):
246 try:
247 res = requests.get('http://127.0.0.1:%s/' % WEBPORT)
248 available = True
249 break
2e8f4675
O
250 except HTTPError as http_err:
251 print(f'HTTP error occurred: {http_err}')
252 except Exception as err:
253 print(f'Other error occurred: {err}')
ab6031a1 254 time.sleep(1)
a1e51a8a
CH
255
256if not available:
541bb91b 257 print("Webserver port not reachable after 10 tries, giving up.")
7992c698
CH
258 serverproc.terminate()
259 serverproc.wait()
ab6031a1 260 print("==STDOUT===")
02e8a66f 261 print(serverproc.stdout.read())
ab6031a1 262 print("==STDERRR===")
02e8a66f 263 print(serverproc.stderr.read())
a1e51a8a
CH
264 sys.exit(2)
265
541bb91b 266print("Query for example.com/A to create statistic data...")
0567c609 267run_check_call([sdig, "127.0.0.1", str(DNSPORT), "example.com", "A"])
118d3b31 268
541bb91b 269print("Running tests...")
7992c698 270returncode = 0
1a152698
CH
271test_env = {}
272test_env.update(os.environ)
7cbc5255 273test_env.update({
c563cbe5 274 'WEBPASSWORD': WEBPASSWORD,
7992c698 275 'WEBPORT': str(WEBPORT),
7cbc5255
CH
276 'APIKEY': APIKEY,
277 'DAEMON': daemon,
0bbd0a64
KM
278 'BACKEND': backend,
279 'MYSQL_DB': MYSQL_DB,
280 'MYSQL_USER': MYSQL_USER,
281 'MYSQL_HOST': MYSQL_HOST,
282 'MYSQL_PASSWD': MYSQL_PASSWD,
283 'PGSQL_DB': PGSQL_DB,
7cbc5255 284 'SQLITE_DB': SQLITE_DB,
0bbd0a64 285 'LMDB_DB': LMDB_DB,
7cbc5255 286 'PDNSUTIL_CMD': ' '.join(PDNSUTIL_CMD),
d19c22a1
CHB
287 'SDIG': sdig,
288 'DNSPORT': str(DNSPORT)
7cbc5255 289})
1a152698
CH
290
291try:
541bb91b 292 print("")
db7b0230 293 run_check_call(["pytest", "--junitxml=pytest.xml", "-v"] + tests, env=test_env)
1a152698 294except subprocess.CalledProcessError as ex:
7992c698 295 returncode = ex.returncode
1a152698 296finally:
5f8fa6d4 297 if wait:
541bb91b 298 print("Waiting as requested, press ENTER to stop.")
5f8fa6d4 299 raw_input()
7992c698
CH
300 serverproc.terminate()
301 serverproc.wait()
ab6031a1
O
302 print("==STDOUT===")
303 print(serverproc.stdout.read())
304 print("==STDERRR===")
305 print(serverproc.stderr.read())
1a152698 306
7992c698 307sys.exit(returncode)