ansible-taler-exchange

Ansible playbook to deploy a production Taler Exchange
Log | Files | Refs | README | LICENSE

test_nginx_latency.py (3188B)


      1 #!/usr/bin/env python3
      2 """Exercise the exchange latency classifier with the Lua interpreter."""
      3 import json
      4 from pathlib import Path
      5 import re
      6 import subprocess
      7 import unittest
      8 
      9 from jinja2 import Environment, StrictUndefined
     10 
     11 REPO = Path(__file__).resolve().parents[2]
     12 ROUTES = json.loads((REPO / 'roles/monitoring/files/exchange-latency-routes.json').read_text())
     13 
     14 
     15 def render(relative, **values):
     16     env = Environment(undefined=StrictUndefined)
     17     env.filters['to_json'] = json.dumps
     18     return env.from_string((REPO / relative).read_text()).render(
     19         monitoring_nginx_latency_routes=ROUTES, **values)
     20 
     21 
     22 class LatencyTest(unittest.TestCase):
     23     def test_route_allowlist(self):
     24         seen = set()
     25         for row in ROUTES:
     26             key = (row['method'], row['pattern'])
     27             self.assertNotIn(key, seen)
     28             seen.add(key)
     29             self.assertRegex(row['operation'], r'^[a-z][a-z0-9-]*$')
     30             re.compile('^' + row['pattern'] + '$')
     31         self.assertEqual(sum(row['polling'] > 1 and row['method'] == 'GET' for row in ROUTES), 6)
     32 
     33     def test_classifier(self):
     34         source = render('roles/monitoring/templates/exchange-latency.lua.j2')
     35         cases = [
     36             ('POST', '/batch-deposit', '200', '0.005', '0.001', '0.004', 'deposit'),
     37             ('GET', '/config', '304', '0.000', '-', '-', 'config'),
     38             ('GET', '/reserves/SECRET', '404', '0.1', '-', '-', 'reserves'),
     39             ('POST', '/withdraw', '502', '0.5', '0.001, 0.002', '0.1, 0.3', 'withdraw'),
     40             ('POST', '/coins/SECRET/refund', '200', '11.001', '0.001 : 0.002', '0.2 : 10.1', 'coins-refund'),
     41             ('PATCH', '/unknown/SECRET', '400', '0.2', '-', '-', 'other'),
     42             ('DELETE', '/purses/SECRET', '204', '0.001', '-', '-', 'purses'),
     43         ]
     44         for method, uri, status, duration, uct, urt, operation in cases:
     45             line = f'm={method} uri={uri} s={status} uct={uct} urt={urt} rt={duration} rl=10 bs=20'
     46             source += '\ndo\nlocal _, _, r = exchange_latency("test", 42, {log=' + json.dumps(line) + '})\n'
     47             source += f'assert(r.valid == "true" and r.operation == "{operation}")\n'
     48             source += f'assert(r.duration == {duration} and r.method == "{method}" and r.status == "{status}")\n'
     49             source += 'assert(r.uri == nil and r.log == nil)\nend\n'
     50         for line in ['garbage', 'm=GET uri=/unknown s=200 uct=- urt=- rt=0.1 rl=1 bs=1',
     51                      'm=HEAD uri=/config s=200 uct=- urt=- rt=0.1 rl=1 bs=1',
     52                      'm=POST uri=/withdraw s=999 uct=- urt=- rt=0.1 rl=1 bs=1',
     53                      'm=POST uri=/withdraw s=200 uct=- urt=- rt=-1 rl=1 bs=1',
     54                      'm=POST uri=/withdraw s=200 uct=- urt=- rt=NaN rl=1 bs=1',
     55                      'm=POST uri=/withdraw s=200 uct=- urt=- rt=' + '9' * 400 + ' rl=1 bs=1']:
     56             source += '\ndo\nlocal _, _, r = exchange_latency("test", 42, {log=' + json.dumps(line) + '})\nassert(r.valid == "false")\nend\n'
     57         result = subprocess.run(['lua', '-'], input=source, text=True, capture_output=True)
     58         self.assertEqual(result.returncode, 0, result.stderr)
     59 
     60 
     61 if __name__ == '__main__':
     62     unittest.main()