Skip to content

Add basic h2 proto tests #155

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 13, 2020
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion framework/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
__all__ = ['client', 'deproxy_client', 'deproxy_manager', 'deproxy_server',
'nginx_server', 'templates', 'tester', 'wrk_client', 'port_checks']
'nginx_server', 'templates', 'tester', 'wrk_client', 'port_checks',
'external_client']
3 changes: 3 additions & 0 deletions framework/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ def set_uri(self, uri):
They use file with list of uris instead. Don't force clients to use
uri field.
"""
if not uri:
self.uri = ''
return
proto = 'https://' if self.ssl else 'http://'
self.uri = ''.join([proto, self.server_addr, uri])

Expand Down
19 changes: 19 additions & 0 deletions framework/external_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from . import client


__author__ = 'Tempesta Technologies, Inc.'
__copyright__ = 'Copyright (C) 2020 Tempesta Technologies, Inc.'
__license__ = 'GPL2'

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a comment what's the new class is for.

class ExternalTester(client.Client):

def __init__(self, cmd_args, **kwargs):
client.Client.__init__(self, **kwargs)
self.options = [cmd_args]

def form_command(self):
cmd = ' '.join([self.bin] + self.options)
return cmd

def parse_out(self, stdout, stderr):
return True
12 changes: 12 additions & 0 deletions framework/tester.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import framework.wrk_client as wrk_client
import framework.deproxy_client as deproxy_client
import framework.deproxy_manager as deproxy_manager
import framework.external_client as external_client

from framework.templates import fill_template, populate_properties

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

def __create_client_external(self, client_descr):
cmd_args = fill_template(client_descr['cmd_args'], client_descr)
ext_client = external_client.ExternalTester(binary=client_descr['binary'],
cmd_args=cmd_args,
server_addr=None,
uri=None)
return ext_client

def __create_client(self, client):
populate_properties(client)
ssl = client.setdefault('ssl', False)
Expand All @@ -167,6 +177,8 @@ def __create_client(self, client):
self.__clients[cid].set_rps(client.get('rps', 0))
elif client['type'] == 'wrk':
self.__clients[cid] = self.__create_client_wrk(client, ssl)
elif client['type'] == 'external':
self.__clients[cid] = self.__create_client_external(client)

def __create_backend(self, server):
srv = None
Expand Down
3 changes: 3 additions & 0 deletions h2/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__all__ = ['test_h2_specs']

# vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4
104 changes: 104 additions & 0 deletions h2/test_h2_specs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
from helpers import tf_cfg
from framework import tester

__author__ = 'Tempesta Technologies, Inc.'
__copyright__ = 'Copyright (C) 2020 Tempesta Technologies, Inc.'
__license__ = 'GPL2'

NGINX_CONFIG = """
pid ${pid};
worker_processes auto;

events {
worker_connections 1024;
use epoll;
}

http {
keepalive_timeout ${server_keepalive_timeout};
keepalive_requests ${server_keepalive_requests};
sendfile on;
tcp_nopush on;
tcp_nodelay on;

open_file_cache max=1000;
open_file_cache_valid 30s;
open_file_cache_min_uses 2;
open_file_cache_errors off;

# [ debug | info | notice | warn | error | crit | alert | emerg ]
# Fully disable log errors.
error_log /dev/null emerg;

# Disable access log altogether.
access_log off;

server {
listen ${server_ip}:8000;

location / {
return 200;
}
location /nginx_status {
stub_status on;
}
}
}
"""

TEMPESTA_CONFIG = """
listen 443 proto=h2;

srv_group default {
server ${server_ip}:8000;
}
vhost default {
tls_certificate ${general_workdir}/tempesta.crt;
tls_certificate_key ${general_workdir}/tempesta.key;

proxy_pass default;
}

cache 0;

"""

class H2Spec(tester.TempestaTest):
'''Tests for h2 proto implementation. Run h2spec utility against Tempesta.
Simply check return code and warnings in system log for test errors.
'''

clients = [
{
'id' : 'h2spec',
'type' : 'external',
'binary' : 'h2spec',
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add h2spec to requirements in Readme.md . Also maybe update tests_config.ini.sample as well that we'll have the test by default?

'ssl' : True,
'cmd_args' : '-tkh ${tempesta_ip}'
},
]

backends = [
{
'id' : 'nginx',
'type' : 'nginx',
'port' : '8000',
'status_uri' : 'http://${server_ip}:8000/nginx_status',
'config' : NGINX_CONFIG,
}
]

tempesta = {
'config' : TEMPESTA_CONFIG,
}

def test_h2_specs(self):
h2spec = self.get_client('h2spec')
# TODO: for now run only simple test to check http2 connectivity
# After all h2-related issues will be fixed, remove the line
h2spec.options.append('generic/4')

self.start_all_servers()
self.start_tempesta()
self.start_all_clients()
self.wait_while_busy(h2spec)
5 changes: 3 additions & 2 deletions helpers/remote.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ def run_cmd(self, cmd, timeout=DEFAULT_TIMEOUT, ignore_stderr=False,
stderr=stderr_pipe, env=env_full) as p:
try:
stdout, stderr = p.communicate(timeout)
assert p.returncode == 0, "Return code is not 0."
assert p.returncode == 0, \
"Cmd: '%s' return code is not 0 (%d)." % (cmd, p.returncode)
except Exception as e:
if not err_msg:
err_msg = ("Error running command '%s' on %s" %
Expand Down Expand Up @@ -221,7 +222,7 @@ def remove_file(self, filename):

def wait_available(self):
tf_cfg.dbg(3, '\tWaiting for %s node' % self.type)
timeout = float(tf_cfg.cfg.get(self.type, 'unavaliable_timeout'))
timeout = float(tf_cfg.cfg.get(self.type, 'unavaliable_timeout'))
t0 = time.time()
while True:
t = time.time()
Expand Down
3 changes: 2 additions & 1 deletion helpers/tempesta.py
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,8 @@ def __handle_tls(self, custom_cert):
"Two or more certificates configured, please use custom_cert" \
" option in Tempesta configuration"
cfg[k] = v
if not cfg.has_key('listen') or not 'https' in cfg['listen']:
if not cfg.has_key('listen') or not \
any(proto in cfg['listen'] for proto in ['https', 'h2']):
return
cert_path, key_path = cfg['tls_certificate'], cfg['tls_certificate_key']
cgen = CertGenerator(cert_path, key_path, True)
Expand Down