Skip to content
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

Testing framework #679

Merged
merged 75 commits into from
Mar 14, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
a357477
func tests: add tests framework with support of benchmark utilities
vankoven Feb 7, 2017
d2a9533
func tests: add functional tests for rr scheduler
vankoven Feb 7, 2017
19295c7
func tests: add more helpers
vankoven Feb 7, 2017
ef5bd45
func test: add hash scheduller test
vankoven Feb 7, 2017
3aa1e01
func tests: add readme
vankoven Feb 8, 2017
7022a9e
func tests: add a few comments
vankoven Feb 8, 2017
6662d4f
func tests: move showing performance counters to separate function
vankoven Feb 8, 2017
f075605
func tests: HACK: ignore some tempesta error counters when using wrk …
vankoven Feb 8, 2017
e3d8109
func tests: improve Client helper class: easy configuration of option…
vankoven Feb 9, 2017
5516444
func tests: graceful tests interrupt
vankoven Feb 9, 2017
c016c48
func tests: add ApacheBenchmark helper
vankoven Feb 9, 2017
abde176
func tests: add siege support
vankoven Feb 9, 2017
4259846
func tests: fix tempesta's "message other error" workaround
vankoven Feb 9, 2017
d7a8fa9
func tests: add possibility to debug files copied to remote host
vankoven Feb 9, 2017
69966c0
func tests: remote: fix aprsetter return values
vankoven Feb 10, 2017
791a06a
func tests: static arp requests doesn't affect performance.
vankoven Feb 10, 2017
dbe8e29
func tests: fix default concurent connections
vankoven Feb 10, 2017
be99f4e
func tests: switch to python 2
vankoven Feb 10, 2017
9f85d98
func tests: update docs, add sample config, forbid running without co…
vankoven Feb 13, 2017
ecdaa09
func tests: siege remove debugging output
vankoven Feb 13, 2017
6cb8830
func tests: update readme to suit python 2 notation
vankoven Feb 14, 2017
7796039
func tests: catch all exceptions raised by paramiko
vankoven Feb 14, 2017
728bb7a
func tests: add default uri for siege
vankoven Feb 14, 2017
a4d6bd0
func tests: use print function instead of operator
vankoven Feb 14, 2017
96fb87d
tests: cookies stress test
vankoven Feb 15, 2017
da5174d
tests: normalize configuration options on start
vankoven Feb 17, 2017
bd1bb78
tests: fix small errors on client run
vankoven Feb 17, 2017
3f654b3
tests: reduce count `mkdir` commands count
vankoven Feb 17, 2017
0dc7ccd
tests: concatenate strings in python way, update error messages
vankoven Feb 17, 2017
774732f
tests: make asserts more friendly
vankoven Feb 20, 2017
b761b57
tests: fix issue in starting daemons, that does not close stderr
vankoven Feb 20, 2017
b3ff094
tests: speedup by running clients on test nodes
vankoven Feb 21, 2017
21adb81
tests: add comments for asserts
vankoven Feb 21, 2017
c226a08
tests: add debug message, when run clients
vankoven Feb 21, 2017
1ea2bf6
tests: use subprocess32 to use timeout for subprocesses
vankoven Feb 21, 2017
eca823c
tests: get rid of http server states
vankoven Feb 21, 2017
9fc98ad
tests: disable descriptions
vankoven Feb 22, 2017
06ce319
test: divide test case and test framework errors
vankoven Feb 22, 2017
8f3e1f8
tests: reworked remotes: fail tests on errors, don't pass them up
vankoven Feb 23, 2017
07aedf7
testd: fix python lint checks
vankoven Feb 25, 2017
1888c04
tests: raise better framework errors
vankoven Feb 27, 2017
33f2acd
tests: fix error
vankoven Feb 27, 2017
48f0927
tests: forward stderr of local commands to /dev/null if not needed
vankoven Feb 27, 2017
146a3bd
tests: remove outdated tests
vankoven Feb 28, 2017
4d2d762
tests: update readme
vankoven Feb 28, 2017
bb72738
tests: add missing copyright
vankoven Feb 28, 2017
57ad22d
tests: limit max count of threads when starting servers
vankoven Feb 28, 2017
762b5cc
tests: make smaller timeout for completing commands
vankoven Mar 3, 2017
bd877a2
tests: deproxy: add requests parser
vankoven Mar 6, 2017
2eae3ee
tests: update readme
vankoven Mar 6, 2017
b688941
tests: deproxy: add tests add headers collection
vankoven Mar 6, 2017
f489b20
tests: deproxy: implement resp and req classes
vankoven Mar 6, 2017
cceb5bf
tests: deproxy: add parse body support
vankoven Mar 7, 2017
d55a422
tests: deproxy base class
vankoven Mar 7, 2017
a57d7cb
tests: fix str function
vankoven Mar 7, 2017
f965953
tests: move base testers classes to separate module
vankoven Mar 7, 2017
a1f1147
test: fix default parameters
vankoven Mar 7, 2017
60da41d
tests: deproxy: fix errors
vankoven Mar 7, 2017
fe32f9a
test: deproxy improvements
vankoven Mar 8, 2017
f8157fa
tests: better closing of stress test
vankoven Mar 8, 2017
60dc6dc
tests: deproxy: fix chunked encoding
vankoven Mar 9, 2017
0c0c1c3
tests: deproxy add http message fabric
vankoven Mar 9, 2017
692e335
tests: regression: add shutdown test
vankoven Mar 9, 2017
d57b48b
tests: regression: add tests for server connections failovering
vankoven Mar 9, 2017
665fd9b
tests: add tests for caching responses
vankoven Mar 9, 2017
3578100
tests: move issue 383 to the regression test, add hash scheduler func…
vankoven Mar 9, 2017
d47f447
tests: deproxy: add update method for messages
vankoven Mar 10, 2017
746571c
tests: functional: add helper function to create chuncked message chain
vankoven Mar 10, 2017
1addc3f
tests: update to suite current master
vankoven Mar 10, 2017
dbe5b58
tests: failovering: wait for more time, since default number of conne…
vankoven Mar 10, 2017
082cbcd
tests: fix setting default values in config
vankoven Mar 10, 2017
e0ad7af
tests: regression: more strict testing of issue #383
vankoven Mar 10, 2017
2f056c1
tests: lower down precision of fair loading of rr scheduler
vankoven Mar 10, 2017
0737f95
tests: cleanup texts
vankoven Mar 13, 2017
44abd17
tests: add http sched tests
vankoven Mar 9, 2017
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
1 change: 1 addition & 0 deletions tempesta_fw/t/functional/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
tests_config.ini
215 changes: 215 additions & 0 deletions tempesta_fw/t/functional/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,215 @@
# Functional Tests for TempestaFW

## Recommended configuration

Running tests during development process can cause crashes to TempestaFW.
Since TempestaFW is implemented as a set of kernel modules it is not convenient
to run testing framework on the same host. It is recommended to run testing
framework on a separated host.

Recommended test-beds:

- Local testing. All parts of the testing framework are running on the same
host. The simpliest configuration to check that current revision of TempestaFW
passes all the functional tests. It is default configuration.
```
┌─────────────────────────────────────────────┐
│ Testing Framework + TempestaFW + Web Server │
└─────────────────────────────────────────────┘
```

- With isolated testing framework. This preset more helpful for development
process, since testing framework itself is isolated from possible kernel
crashes or hangs. This configuration is recommended for TempestaFW developers.
```
┌───────────────────┐
│ Testing Framework ├────┐
└──────┬────────────┘ │ Management over SSH
│ ┌──┴──────────────────────┐
│ │ TempestaFW + Web Server │
│ └───────────────┬─────────┘
└──────────────────────────────┘
Separated network for test traffic
```

- Fully distributed. 3 different hosts with their own roles are used. This
configuration isolates traffic generated by benchmark utilities and traffic
generators in test network. Handy for stress and performance testing but require
a lot of resources.
```
┌───────────────────┐
│ Testing Framework ├────┐
└──────┬────────────┘ │ Management over SSH
│ ├────────────────────┐
│ ┌──────┴─────┐ ┌─────┴──────┐
│ │ TempestaFW │ │ Web Server │
│ └──────┬─────┘ └─────┬──────┘
└─────────────────┴────────────────────┘
Separated network for test traffic
```

There is two different models of tests: workload tests and pure functional
tests. Workload tests uses fully functional HTTP benchmark programs (ab, siege,
wrk) and HTTP servers (Apache, nginx) to check TempestaFW behaviour. This type
of tests is used for schedulers, stress and performance testing.

Pure functional tests check internal logic. Here combined HTTP client-server
server is used. It sends HTTP messages to TempestaFW, analyses how they are
forwarded to server, and vice versa, which server connections are used.


## Requirements

- Host for testing framework: `Python2`, `python2-paramiko`,
`python-configparser`, `python-subprocess32`, `wrk`, `ab`, `siege`
- All hosts except previous one: `sftp-server`
- Host for running TempestaFW: Linux kernel with Tempesta, TempestaFW sources
- Host for running server: `nginx`, web content directory accessible by nginx

`wrk` is an HTTP benchmarking tool, available from [Github](https://github.com/wg/wrk).

`ab` is Apache benchmark tool, that can be found in `apache2-utils` package in
Debian or `httpd-tools` in CentOS.

`siege` is an HTTP benchmarking tool, available in `siege` package in Debian
and `siege` in [EPEL repository](https://dl.fedoraproject.org/pub/epel/7/x86_64/s/siege-4.0.2-2.el7.x86_64.rpm)
in CentOS.

Unfortunately, CentOS does not have `python-subprocess32` package, but it can be
downloaded from [CentOS CBS](https://cbs.centos.org/koji/buildinfo?buildID=10904)

Testing framework manages other hosts via SSH protocol, so the host running
testing framework must be able to be authenticated on other hosts by the key.
That can be done using `ssh-copy-id`.


## Run tests

### Configuration

Testing framework is configured via `tests_config.ini' file. Example
configuration is described in `tests_config.ini.sample' file.
You can also create default tests configuration by calling:

```sh
$ ./run_tests.py -d
```

There is 4 sections in configuration: `General`, `Client`, `Tempesta`, `Server`.

#### General Section

`General` section describes the options related to testing framework itself.

`verbose`: verbose level of output:
- `0` - quiet mode, result of each test is shown by symbols. `.` - passed, `F` -
failed, `u` - unexpected success, `x` - expected failure. `s` - skipped;
- `1` - Show test names and doc strings;
- `2` - Show tests names and performance counters;
- `3` - Full debug output.

`Duration` option controls duration in seconds of each workload test. Use small
values to obtain results quickly add large for more heavy stress tests. Default
is `10` seconds.

This group of options can be overridden by command line options, for more
information run tests with `-h` key.
```sh
$ ./run_tests.py -h
```

#### Client Section

`workdir` - directory to place temporary files (configs, pidfiles, etc.) on the
host. R/W access is required, must be absolute path.

`ab`, `siege` and `wrk` - absolute path to corresponding binaries.

#### Tempesta Section

`ip` - IPv4/IPv6 address of the host in test network. Used to run `wrk`,
`tempesta`, `nginx` and others with right parameters. Default is `127.0.0.1`.

`hostname`, `port`, `user` - this options describes "management" interface of
the host. Testing framework uses this fields to connect to each test node.

Options above are common for hosts `Server` and `Tempesta` and present in each
section.

`workdir` - Directory with TempestaFW sources. Must be absolute path.

#### Server Section

Options listed in [Tempesta Section](#tempesta-section): `ip`, `hostname`,
`port`, `user` are also applied to this section.

`workdir` - directory to place temporary files (configs, pidfiles, etc.) on the
host. R/W access is required, must be absolute path.

`nginx` - absolute path to corresponding binary.

`resourses` - absolute path to directory with sample web pages. Must be
reachable by `nginx`.


### Run tests

To run all the tests simply run:
```sh
$ ./run_tests.py
Copy link
Contributor

Choose a reason for hiding this comment

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

Probably we need the file only. Now run_all_tests.sh is just broken, so it's better to remove it at all

```

Copy link
Contributor

Choose a reason for hiding this comment

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

There is some issue with the test suit. I can't run it on my CentOS 7 VM, please see the trace at the below. Probably the issue can be easily fixed or just analyzed at least. However, the fundamental problem with the test suite is improper exceptions handling: it prints inadequate call trace instead of printing some user friendly message. The call trace is familiar to the test developer only.

    [root@localhost functional]# ./run_tests.py -f
    
    ----------------------------------------------------------------------
    Running functional tests...
    ----------------------------------------------------------------------
    
    E
    ======================================================================
    ERROR: sched.test_sched_hash (unittest.loader._FailedTest)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/usr/lib64/python3.4/unittest/case.py", line 59, in testPartExecutor
        yield
      File "/usr/lib64/python3.4/unittest/case.py", line 618, in run
        testMethod()
      File "/usr/lib64/python3.4/unittest/loader.py", line 33, in testFailure
        raise self._exception
    ImportError: Failed to import test module: sched.test_sched_hash
    Traceback (most recent call last):
      File "/usr/lib64/python3.4/unittest/loader.py", line 323, in _find_tests
        module = self._get_module_from_name(name)
      File "/usr/lib64/python3.4/unittest/loader.py", line 301, in _get_module_from_name
        __import__(name)
      File "/root/tempesta/tempesta_fw/t/functional/sched/test_sched_hash.py", line 2, in <module>
        from helpers import tfw_test, tempesta
      File "/root/tempesta/tempesta_fw/t/functional/helpers/tfw_test.py", line 2, in <module>
        from . import tf_cfg, control, tempesta
      File "/root/tempesta/tempesta_fw/t/functional/helpers/control.py", line 4, in <module>
        from . import tf_cfg, remote, nginx, tempesta, siege
      File "/root/tempesta/tempesta_fw/t/functional/helpers/remote.py", line 194, in <module>
        assert(setter.fill_arp())
    AssertionError
    
    
    ----------------------------------------------------------------------
    Ran 1 test in 0.001s
    
    FAILED (errors=1)
    [root@localhost functional]# cat tests_config.ini 
    [Tempesta]
    mac = ff:ff:ff:ff:ff:ff
    dir = /root/tempesta
    hostname = localhost
    ip = 127.0.0.1
    user = root
    port = 22
    
    [Server]
    nginx = nginx
    mac = ff:ff:ff:ff:ff:ff
    workdir = /opt/nginx-1.11.3/
    hostname = localhost
    ip = 127.0.0.1
    user = root
    resourses = /var/www/html/
    port = 22
    
    [General]
    arp = True
    duration = 10
    verbose = 0
    concurent_connections = -1
    
    [Client]
    ab = ab
    wrk = wrk
    mac = ff:ff:ff:ff:ff:ff
    workdir = /root/client
    hostname = localhost
    ip = 127.0.0.1
    user = root
    siege = siege
    port = 22
    
    [root@localhost functional]# pwd
    /root/tempesta/tempesta_fw/t/functional

The unittest module can be used from the command line to run tests from modules,
classes or even individual test methods:
```sh
$ python2 -m unittest test_module1 test_module2
$ python2 -m unittest test_module.TestClass
$ python2 -m unittest test_module.TestClass.test_method
```
Next command will run all tests from specified directory:
```sh
$ python2 -m unittest discover <directory>
```
In this case verbosity of the tests names is controlled separately from
configuration flie:
```sh
$ python2 -m unittest -v test_module.TestClass
```
For a list of all the command-line options:
```sh
$ python2 -m unittest -h
```


## Adding new tests

Adding new tests is easy. First, create new Python file in the new Python module
(directory) or existing one.
Name of the file must be started with `test_`
```sh
$ mkdir my_test
$ touch my_test/test_some_feature.py
$ echo "__all__ = [ 'test_some_feature' ]" >> my_test/__init.py__
```

Import module `unittest`, and derive you test class from `stress.StressTest`
or `functional.FunctionalTest`
class from `testers` module. Add functions started with `test_`. Test class may
have any name. Here is example of `my_test/test_some_feature.py`:
```python
import unittest
from testers import stress

class MyTester(stress.StressTest):
""" Test class documentation. """

tempesta_defconfig = 'cache 0;\n'

def test_some_featue(self):
""" Test documentation. """
self.generic_test_routine(self.tempesta_defconfig)
```

Tests can be skipped or marked as expected to fail.
More info at [Python documentation](https://docs.python.org/3/library/unittest.html).

1 change: 1 addition & 0 deletions tempesta_fw/t/functional/cache/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__all__ = ['check_cache']
100 changes: 100 additions & 0 deletions tempesta_fw/t/functional/cache/test_cache.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
"""Functional tests of caching responses."""

from __future__ import print_function
import unittest
from helpers import deproxy, tf_cfg, tempesta
from testers import functional

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

# TODO: add tests for RFC compliance

class TestCacheDisabled(functional.FunctionalTest):

messages = 10

# Disable caching
cache_mode = 0

def chain(self, uri='/', cache_alowed=True):
if self.cache_mode == 0:
cache_alowed = False
if cache_alowed:
return cache_chains(self.messages, uri=uri)
return proxy_chains(self.messages, uri=uri)

def test_cache_fulfill_all(self):
config = ('cache %d;\n'
'cache_fulfill * *;\n' % self.cache_mode)
self.generic_test_routine(config, self.chain(cache_alowed=True))

def test_cache_bypass_all(self):
config = ('cache %d;\n'
'cache_bypass * *;\n' % self.cache_mode)
self.generic_test_routine(config, self.chain(cache_alowed=False))

def mixed_config(self):
return ('cache %d;\n'
'cache_fulfill suffix ".jpg" ".png";\n'
'cache_bypass suffix ".avi";\n'
'cache_bypass prefix "/static/dynamic_zone/";\n'
'cache_fulfill prefix "/static/";\n'
% self.cache_mode)

def test_cache_fulfill_suffix(self):
self.generic_test_routine(
self.mixed_config(),
self.chain(cache_alowed=True, uri='/picts/bear.jpg'))

def test_cache_fulfill_suffix_2(self):
self.generic_test_routine(
self.mixed_config(),
self.chain(cache_alowed=True, uri='/jsnfsjk/jnd.png'))

def test_cache_bypass_suffix(self):
self.generic_test_routine(
self.mixed_config(),
self.chain(cache_alowed=False, uri='/howto/film.avi'))

def test_cache_bypass_prefix(self):
self.generic_test_routine(
self.mixed_config(),
self.chain(cache_alowed=False,
uri='/static/dynamic_zone/content.html'))

def test_cache_fulfill_prefix(self):
self.generic_test_routine(
self.mixed_config(),
self.chain(cache_alowed=True, uri='/static/content.html'))


class TestCacheSharding(TestCacheDisabled):

# Sharding mode.
cache_mode = 1

class TestCacheReplicated(TestCacheDisabled):

# Replicated mode.
cache_mode = 2


def cache_chain(uri):
cached_chain = functional.base_message_chain(uri=uri)
cached_chain.no_forward()
return cached_chain

def proxy_chain(uri):
return functional.base_message_chain(uri=uri)

def cache_chains(count, uri='/'):
chains = [proxy_chain(uri)]
chain = cache_chain(uri)
cached_chains = [chain for i in range (1, count)]
return chains + cached_chains

def proxy_chains(count, uri='/'):
chain = proxy_chain(uri)
return [chain for i in range (count)]
2 changes: 1 addition & 1 deletion tempesta_fw/t/functional/helpers/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__all__ = [ 'be', 'cli', 'tfw' ]
__all__ = ['tf_cfg', 'deproxy', 'nginx', 'tempesta', 'siege', 'error']
Loading