import time
import pytest
from unit.applications.lang.python import ApplicationPython
from unit.option import option
prerequisites = {'modules': {'python': 'any'}}
client = ApplicationPython()
def load(script):
client.load(script)
assert 'success' in client.conf(
f'"{option.temp_dir}/access.log"', 'access_log'
), 'access_log configure'
def set_format(log_format):
assert 'success' in client.conf(
{
'path': f'{option.temp_dir}/access.log',
'format': log_format,
},
'access_log',
), 'access_log format'
def set_if(condition):
assert 'success' in client.conf(f'"{condition}"', 'access_log/if')
def test_access_log_keepalive(wait_for_record):
load('mirror')
assert client.get()['status'] == 200, 'init'
(_, sock) = client.post(
headers={
'Host': 'localhost',
'Connection': 'keep-alive',
},
start=True,
body='01234',
read_timeout=1,
)
assert (
wait_for_record(r'"POST / HTTP/1.1" 200 5', 'access.log') is not None
), 'keepalive 1'
_ = client.post(sock=sock, body='0123456789')
assert (
wait_for_record(r'"POST / HTTP/1.1" 200 10', 'access.log') is not None
), 'keepalive 2'
def test_access_log_pipeline(wait_for_record):
load('empty')
client.http(
b"""GET / HTTP/1.1
Host: localhost
Referer: Referer-1
GET / HTTP/1.1
Host: localhost
Referer: Referer-2
GET / HTTP/1.1
Host: localhost
Referer: Referer-3
Connection: close
""",
raw_resp=True,
raw=True,
)
assert (
wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-1" "-"', 'access.log')
is not None
), 'pipeline 1'
assert (
wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-2" "-"', 'access.log')
is not None
), 'pipeline 2'
assert (
wait_for_record(r'"GET / HTTP/1.1" 200 0 "Referer-3" "-"', 'access.log')
is not None
), 'pipeline 3'
def test_access_log_ipv6(wait_for_record):
load('empty')
assert 'success' in client.conf(
{"[::1]:8080": {"pass": "applications/empty"}}, 'listeners'
)
client.get(sock_type='ipv6')
assert (
wait_for_record(
r'::1 - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"', 'access.log'
)
is not None
), 'ipv6'
def test_access_log_unix(temp_dir, wait_for_record):
load('empty')
addr = f'{temp_dir}/sock'
assert 'success' in client.conf(
{f'unix:{addr}': {"pass": "applications/empty"}}, 'listeners'
)
client.get(sock_type='unix', addr=addr)
assert (
wait_for_record(
r'unix: - - \[.+\] "GET / HTTP/1.1" 200 0 "-" "-"', 'access.log'
)
is not None
), 'unix'
def test_access_log_referer(wait_for_record):
load('empty')
client.get(
headers={
'Host': 'localhost',
'Referer': 'referer-value',
'Connection': 'close',
}
)
assert (
wait_for_record(
r'"GET / HTTP/1.1" 200 0 "referer-value" "-"', 'access.log'
)
is not None
), 'referer'
def test_access_log_user_agent(wait_for_record):
load('empty')
client.get(
headers={
'Host': 'localhost',
'User-Agent': 'user-agent-value',
'Connection': 'close',
}
)
assert (
wait_for_record(
r'"GET / HTTP/1.1" 200 0 "-" "user-agent-value"', 'access.log'
)
is not None
), 'user agent'
def test_access_log_http10(wait_for_record):
load('empty')
client.get(http_10=True)
assert (
wait_for_record(r'"GET / HTTP/1.0" 200 0 "-" "-"', 'access.log')
is not None
), 'http 1.0'
def test_access_log_partial(wait_for_record):
load('empty')
assert client.post()['status'] == 200, 'init'
_ = client.http(b"""GE""", raw=True, read_timeout=1)
time.sleep(1)
assert (
wait_for_record(r'"-" 400 0 "-" "-"', 'access.log') is not None
), 'partial'
def test_access_log_partial_2(wait_for_record):
load('empty')
assert client.post()['status'] == 200, 'init'
client.http(b"""GET /\n""", raw=True)
assert (
wait_for_record(r'"-" 400 \d+ "-" "-"', 'access.log') is not None
), 'partial 2'
def test_access_log_partial_3(wait_for_record):
load('empty')
assert client.post()['status'] == 200, 'init'
_ = client.http(b"""GET / HTTP/1.1""", raw=True, read_timeout=1)
time.sleep(1)
assert (
wait_for_record(r'"-" 400 0 "-" "-"', 'access.log') is not None
), 'partial 3'
def test_access_log_partial_4(wait_for_record):
load('empty')
assert client.post()['status'] == 200, 'init'
_ = client.http(b"""GET / HTTP/1.1\n""", raw=True, read_timeout=1)
time.sleep(1)
assert (
wait_for_record(r'"-" 400 0 "-" "-"', 'access.log') is not None
), 'partial 4'
@pytest.mark.skip('not yet')
def test_access_log_partial_5(wait_for_record):
load('empty')
assert client.post()['status'] == 200, 'init'
client.get(headers={'Connection': 'close'})
assert (
wait_for_record(r'"GET / HTTP/1.1" 400 \d+ "-" "-"', 'access.log')
is not None
), 'partial 5'
def test_access_log_get_parameters(wait_for_record):
load('empty')
client.get(url='/?blah&var=val')
assert (
wait_for_record(
r'"GET /\?blah&var=val HTTP/1.1" 200 0 "-" "-"', 'access.log'
)
is not None
), 'get parameters'
def test_access_log_delete(search_in_file):
load('empty')
assert 'success' in client.conf_delete('access_log')
client.get(url='/delete')
assert search_in_file(r'/delete', 'access.log') is None, 'delete'
def test_access_log_change(temp_dir, wait_for_record):
load('empty')
client.get()
assert 'success' in client.conf(f'"{temp_dir}/new.log"', 'access_log')
client.get()
assert (
wait_for_record(r'"GET / HTTP/1.1" 200 0 "-" "-"', 'new.log')
is not None
), 'change'
def test_access_log_format(wait_for_record):
load('empty')
def check_format(log_format, expect, url='/'):
set_format(log_format)
assert client.get(url=url)['status'] == 200
assert wait_for_record(expect, 'access.log') is not None, 'found'
log_format = 'BLAH\t0123456789'
check_format(log_format, log_format)
check_format('$uri $status $uri $status', '/ 200 / 200')
def test_access_log_variables(wait_for_record):
load('mirror')
# $body_bytes_sent
set_format('$uri $body_bytes_sent')
body = '0123456789' * 50
client.post(url='/bbs', body=body, read_timeout=1)
assert (
wait_for_record(fr'^\/bbs {len(body)}$', 'access.log') is not None
), '$body_bytes_sent'
def test_access_log_if(search_in_file, wait_for_record):
load('empty')
set_format('$uri')
def try_if(condition):
set_if(condition)
assert client.get(url=f'/{condition}')['status'] == 200
# const
try_if('')
try_if('0')
try_if('false')
try_if('undefined')
try_if('!')
try_if('!null')
try_if('1')
# variable
set_if('$arg_foo')
assert client.get(url='/bar?bar')['status'] == 200
assert client.get(url='/foo_empty?foo')['status'] == 200
assert client.get(url='/foo?foo=1')['status'] == 200
# check results
assert wait_for_record(r'^/foo$', 'access.log') is not None
assert search_in_file(r'^/$', 'access.log') is None
assert search_in_file(r'^/0$', 'access.log') is None
assert search_in_file(r'^/false$', 'access.log') is None
assert search_in_file(r'^/undefined$', 'access.log') is None
assert search_in_file(r'^/!$', 'access.log') is not None
assert search_in_file(r'^/!null$', 'access.log') is not None
assert search_in_file(r'^/1$', 'access.log') is not None
assert search_in_file(r'^/bar$', 'access.log') is None
assert search_in_file(r'^/foo_empty$', 'access.log') is None
def test_access_log_if_njs(require, search_in_file, wait_for_record):
require({'modules': {'njs': 'any'}})
load('empty')
set_format('$uri')
set_if('`${args.foo == \'1\'}`')
assert client.get(url='/foo_2?foo=2')['status'] == 200
assert client.get(url='/foo_1?foo=1')['status'] == 200
assert wait_for_record(r'^/foo_1$', 'access.log') is not None
assert search_in_file(r'^/foo_2$', 'access.log') is None
def test_access_log_incorrect(temp_dir, skip_alert):
skip_alert(r'failed to apply new conf')
assert 'error' in client.conf(
f'{temp_dir}/blah/access.log',
'access_log/path',
), 'access_log path incorrect'
assert 'error' in client.conf(
{
'path': f'{temp_dir}/access.log',
'format': '$remote_add',
},
'access_log',
), 'access_log format incorrect'
assert 'error' in client.conf('$arg_', 'access_log/if')