Skip to content

Commit 7e71719

Browse files
committed
Add basic h2 proto tests
Run h2spec utility against Tempesta and evaluate return code. Increase debug level to get h2spec detailed results. A new directive in `tests_config.ini` under section `[Client]` may be required since h2spec is never available through pacage manager and need to be installed from https://github.com/summerwind/h2spec : h2spec = /path/to/h2spec Fix tempesta-tech/tempesta#739
1 parent 852d0a2 commit 7e71719

File tree

8 files changed

+148
-4
lines changed

8 files changed

+148
-4
lines changed

framework/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
__all__ = ['client', 'deproxy_client', 'deproxy_manager', 'deproxy_server',
2-
'nginx_server', 'templates', 'tester', 'wrk_client', 'port_checks']
2+
'nginx_server', 'templates', 'tester', 'wrk_client', 'port_checks',
3+
'external_client']

framework/client.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ def set_uri(self, uri):
6363
They use file with list of uris instead. Don't force clients to use
6464
uri field.
6565
"""
66+
if not uri:
67+
self.uri = ''
68+
return
6669
proto = 'https://' if self.ssl else 'http://'
6770
self.uri = ''.join([proto, self.server_addr, uri])
6871

framework/external_client.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
from . import client
2+
3+
4+
__author__ = 'Tempesta Technologies, Inc.'
5+
__copyright__ = 'Copyright (C) 2020 Tempesta Technologies, Inc.'
6+
__license__ = 'GPL2'
7+
8+
class ExternalTester(client.Client):
9+
10+
def __init__(self, cmd_args, **kwargs):
11+
client.Client.__init__(self, **kwargs)
12+
self.options = [cmd_args]
13+
14+
def form_command(self):
15+
cmd = ' '.join([self.bin] + self.options)
16+
return cmd
17+
18+
def parse_out(self, stdout, stderr):
19+
return True

framework/tester.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
import framework.wrk_client as wrk_client
88
import framework.deproxy_client as deproxy_client
99
import framework.deproxy_manager as deproxy_manager
10+
import framework.external_client as external_client
11+
1012
from framework.templates import fill_template, populate_properties
1113

1214
import socket
@@ -150,6 +152,14 @@ def __create_client_wrk(self, client, ssl):
150152
wrk.set_script(client['id']+"_script", content="")
151153
return wrk
152154

155+
def __create_client_external(self, client_descr):
156+
cmd_args = fill_template(client_descr['cmd_args'], client_descr)
157+
ext_client = external_client.ExternalTester(binary=client_descr['binary'],
158+
cmd_args=cmd_args,
159+
server_addr=None,
160+
uri=None)
161+
return ext_client
162+
153163
def __create_client(self, client):
154164
populate_properties(client)
155165
ssl = client.setdefault('ssl', False)
@@ -167,6 +177,8 @@ def __create_client(self, client):
167177
self.__clients[cid].set_rps(client.get('rps', 0))
168178
elif client['type'] == 'wrk':
169179
self.__clients[cid] = self.__create_client_wrk(client, ssl)
180+
elif client['type'] == 'external':
181+
self.__clients[cid] = self.__create_client_external(client)
170182

171183
def __create_backend(self, server):
172184
srv = None

h2/__init__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
__all__ = ['test_h2_specs']
2+
3+
# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4

h2/test_h2_specs.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
from helpers import tf_cfg
2+
from framework import tester
3+
4+
__author__ = 'Tempesta Technologies, Inc.'
5+
__copyright__ = 'Copyright (C) 2020 Tempesta Technologies, Inc.'
6+
__license__ = 'GPL2'
7+
8+
NGINX_CONFIG = """
9+
pid ${pid};
10+
worker_processes auto;
11+
12+
events {
13+
worker_connections 1024;
14+
use epoll;
15+
}
16+
17+
http {
18+
keepalive_timeout ${server_keepalive_timeout};
19+
keepalive_requests ${server_keepalive_requests};
20+
sendfile on;
21+
tcp_nopush on;
22+
tcp_nodelay on;
23+
24+
open_file_cache max=1000;
25+
open_file_cache_valid 30s;
26+
open_file_cache_min_uses 2;
27+
open_file_cache_errors off;
28+
29+
# [ debug | info | notice | warn | error | crit | alert | emerg ]
30+
# Fully disable log errors.
31+
error_log /dev/null emerg;
32+
33+
# Disable access log altogether.
34+
access_log off;
35+
36+
server {
37+
listen ${server_ip}:8000;
38+
39+
location / {
40+
return 200;
41+
}
42+
location /nginx_status {
43+
stub_status on;
44+
}
45+
}
46+
}
47+
"""
48+
49+
TEMPESTA_CONFIG = """
50+
listen 443 proto=h2;
51+
52+
srv_group default {
53+
server ${server_ip}:8000;
54+
}
55+
vhost default {
56+
tls_certificate ${general_workdir}/tempesta.crt;
57+
tls_certificate_key ${general_workdir}/tempesta.key;
58+
59+
proxy_pass default;
60+
}
61+
62+
cache 0;
63+
64+
"""
65+
66+
class H2Spec(tester.TempestaTest):
67+
'''Tests for h2 proto implementation. Run h2spec utility against Tempesta.
68+
Simply check return code and warnings in system log for test errors.
69+
'''
70+
71+
clients = [
72+
{
73+
'id' : 'h2spec',
74+
'type' : 'external',
75+
'binary' : 'h2spec',
76+
'ssl' : True,
77+
'cmd_args' : '-tkh ${tempesta_ip}'
78+
},
79+
]
80+
81+
backends = [
82+
{
83+
'id' : 'nginx',
84+
'type' : 'nginx',
85+
'port' : '8000',
86+
'status_uri' : 'http://${server_ip}:8000/nginx_status',
87+
'config' : NGINX_CONFIG,
88+
}
89+
]
90+
91+
tempesta = {
92+
'config' : TEMPESTA_CONFIG,
93+
}
94+
95+
def test_h2_specs(self):
96+
h2spec = self.get_client('h2spec')
97+
# TODO: for now run only simple test to check http2 connectivity
98+
# After all h2-related issues will be fixed, remove the line
99+
h2spec.options.append('generic/4')
100+
101+
self.start_all_servers()
102+
self.start_tempesta()
103+
self.start_all_clients()
104+
self.wait_while_busy(h2spec)

helpers/remote.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,8 @@ def run_cmd(self, cmd, timeout=DEFAULT_TIMEOUT, ignore_stderr=False,
7979
stderr=stderr_pipe, env=env_full) as p:
8080
try:
8181
stdout, stderr = p.communicate(timeout)
82-
assert p.returncode == 0, "Return code is not 0."
82+
assert p.returncode == 0, \
83+
"Cmd: '%s' return code is not 0 (%d)." % (cmd, p.returncode)
8384
except Exception as e:
8485
if not err_msg:
8586
err_msg = ("Error running command '%s' on %s" %
@@ -221,7 +222,7 @@ def remove_file(self, filename):
221222

222223
def wait_available(self):
223224
tf_cfg.dbg(3, '\tWaiting for %s node' % self.type)
224-
timeout = float(tf_cfg.cfg.get(self.type, 'unavaliable_timeout'))
225+
timeout = float(tf_cfg.cfg.get(self.type, 'unavaliable_timeout'))
225226
t0 = time.time()
226227
while True:
227228
t = time.time()

helpers/tempesta.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,8 @@ def __handle_tls(self, custom_cert):
245245
"Two or more certificates configured, please use custom_cert" \
246246
" option in Tempesta configuration"
247247
cfg[k] = v
248-
if not cfg.has_key('listen') or not 'https' in cfg['listen']:
248+
need_cert = any(proto in cfg['listen'] for proto in ['https', 'h2'])
249+
if not cfg.has_key('listen') or not need_cert:
249250
return
250251
cert_path, key_path = cfg['tls_certificate'], cfg['tls_certificate_key']
251252
cgen = CertGenerator(cert_path, key_path, True)

0 commit comments

Comments
 (0)