paivana

HTTP paywall reverse proxy
Log | Files | Refs | Submodules | README | LICENSE

meson.build (8589B)


      1 # Reverse-proxy integration tests.
      2 #
      3 # Builds the C upstream (libmicrohttpd), the raw-socket pipelining
      4 # client, and — when the toolchains are available — Go and Rust
      5 # upstreams, then runs the shell-driven test driver.
      6 
      7 upstream_mhd = executable(
      8     'upstream_mhd',
      9     'upstream_mhd.c',
     10     dependencies: [mhd_dep],
     11     include_directories: [incdir, configuration_inc],
     12     install: false,
     13 )
     14 
     15 pipeline_client = executable(
     16     'pipeline_client',
     17     'pipeline_client.c',
     18     include_directories: [incdir, configuration_inc],
     19     install: false,
     20 )
     21 
     22 early_response_upstream = executable(
     23     'early_response_upstream',
     24     'early_response_upstream.c',
     25     dependencies: [gnunetutil_dep],
     26     include_directories: [incdir, configuration_inc],
     27     install: false,
     28 )
     29 
     30 # The streaming pair: an origin that serves bodies larger than memory,
     31 # at a controlled rate and in framings a conforming server will not
     32 # emit, and a client that verifies them as they arrive rather than
     33 # storing them.  Both generate the body from its offset, so a 200 MiB
     34 # case costs no disk on either side.
     35 stream_upstream = executable(
     36     'stream_upstream',
     37     'stream_upstream.c',
     38     dependencies: [gnunetutil_dep],
     39     include_directories: [incdir, configuration_inc],
     40     install: false,
     41 )
     42 
     43 stream_client = executable(
     44     'stream_client',
     45     'stream_client.c',
     46     dependencies: [curl_dep],
     47     include_directories: [incdir, configuration_inc],
     48     install: false,
     49 )
     50 
     51 # Unit test for the client-address canonicalisation that the access
     52 # cookie is keyed on.  Links the two backend compilation units it
     53 # exercises; the daemon's globals are supplied by the test itself.
     54 test_client_address = executable(
     55     'test_client_address',
     56     [
     57         'test_client_address.c',
     58         '../backend/paivana-httpd_helper.c',
     59         '../backend/paivana-httpd_cookie.c',
     60     ],
     61     dependencies: [
     62         talerutil_dep,
     63         talermhd_dep,
     64         gnunetutil_dep,
     65         gcrypt_dep,
     66         mhd_dep,
     67         json_dep,
     68         curl_dep,
     69     ],
     70     include_directories: [incdir, configuration_inc, paivana_backend_inc],
     71     install: false,
     72 )
     73 
     74 test('client_address', test_client_address)
     75 
     76 # Unit test for the Set-Cookie line of the access cookie (Path
     77 # encoding, Path grammar, Secure).  Links only the cookie compilation
     78 # unit; the daemon's globals are supplied by the test itself.
     79 test_cookie_header = executable(
     80     'test_cookie_header',
     81     ['test_cookie_header.c', '../backend/paivana-httpd_cookie.c'],
     82     dependencies: [
     83         talerutil_dep,
     84         talermhd_dep,
     85         gnunetutil_dep,
     86         gcrypt_dep,
     87         mhd_dep,
     88         json_dep,
     89         curl_dep,
     90     ],
     91     include_directories: [incdir, configuration_inc, paivana_backend_inc],
     92     install: false,
     93 )
     94 
     95 test('cookie_header', test_cookie_header)
     96 
     97 # Unit test for the access decision the cookie encodes (the time bound,
     98 # the three MAC inputs, the four rejection paths) and for the
     99 # `paivana_id`.  Same shape as the above: only the cookie compilation
    100 # unit, with the daemon's globals supplied by the test.
    101 test_cookie_access = executable(
    102     'test_cookie_access',
    103     ['test_cookie_access.c', '../backend/paivana-httpd_cookie.c'],
    104     dependencies: [
    105         talerutil_dep,
    106         talermhd_dep,
    107         gnunetutil_dep,
    108         gcrypt_dep,
    109         mhd_dep,
    110         json_dep,
    111         curl_dep,
    112     ],
    113     include_directories: [incdir, configuration_inc, paivana_backend_inc],
    114     install: false,
    115 )
    116 
    117 test('cookie_access', test_cookie_access)
    118 
    119 # Prints base64url vectors as the daemon produces them, for
    120 # test_base64url.sh to check paywall.js against.  The paivana ID
    121 # depends on the two encoders agreeing and nothing else forces them to;
    122 # they have already disagreed twice, both times breaking the payment
    123 # path.
    124 base64url_vectors = executable(
    125     'base64url_vectors',
    126     'base64url_vectors.c',
    127     dependencies: [gnunetutil_dep],
    128     include_directories: [incdir, configuration_inc],
    129     install: false,
    130 )
    131 
    132 test(
    133     'base64url',
    134     files('test_base64url.sh'),
    135     env: {
    136         'SRCDIR': meson.current_source_dir(),
    137         'BUILDDIR': meson.current_build_dir(),
    138     },
    139     depends: [base64url_vectors],
    140 )
    141 
    142 test_deps = [
    143     upstream_mhd,
    144     pipeline_client,
    145     early_response_upstream,
    146     stream_upstream,
    147     stream_client,
    148     paivana_httpd_exe,
    149 ]
    150 
    151 go_bin = find_program('go', required: false)
    152 if go_bin.found()
    153     upstream_go = custom_target(
    154         'upstream_go',
    155         input: 'upstream_go.go',
    156         output: 'upstream_go',
    157         command: [go_bin, 'build', '-o', '@OUTPUT@', '@INPUT@'],
    158         build_by_default: true,
    159     )
    160     test_deps += upstream_go
    161 endif
    162 
    163 rustc_bin = find_program('rustc', required: false)
    164 if rustc_bin.found()
    165     upstream_rs = custom_target(
    166         'upstream_rs',
    167         input: 'upstream_rs.rs',
    168         output: 'upstream_rs',
    169         command: [rustc_bin, '-O', '-o', '@OUTPUT@', '@INPUT@'],
    170         build_by_default: true,
    171     )
    172     test_deps += upstream_rs
    173 
    174     # Only benchmark.sh -m paywall uses this, and only to get paivana
    175     # past the template fetch it does before it starts serving.  Built
    176     # here rather than beside it because it needs the same rustc that
    177     # `-m paywall' already requires for upstream_rs, so it costs the
    178     # benchmark no dependency it did not have.
    179     merchant_stub = custom_target(
    180         'merchant_stub',
    181         input: 'merchant_stub.rs',
    182         output: 'merchant_stub',
    183         command: [rustc_bin, '-O', '-o', '@OUTPUT@', '@INPUT@'],
    184         build_by_default: true,
    185     )
    186     test_deps += merchant_stub
    187 endif
    188 
    189 # Under `./configure --enable-sanitizers' the whole project is built
    190 # instrumented, so these are the same tests with ASan and UBSan under
    191 # them rather than extra cases.  Two things are needed to keep that
    192 # mode usable rather than something everyone turns off again:
    193 #
    194 #  - LSan needs the suppression file, or every run fails on one-time
    195 #    allocations in libcurl and libgcrypt that are nothing to do with
    196 #    paivana;
    197 #  - the large cases have to scale down, since 200 MiB through ASan is
    198 #    not a test but a coffee break.  What those cases exercise is the
    199 #    pause/resume interleaving, which is a function of the ring size
    200 #    and not of the total, so a twentieth of the bytes reaches the same
    201 #    transitions.
    202 test_env = {'SRCDIR': meson.current_source_dir(), 'BUILDDIR': meson.current_build_dir(), 'PAIVANA_HTTPD': paivana_httpd_exe.full_path(), 'LSAN_OPTIONS': 'suppressions='
    203     + meson.current_source_dir() / 'lsan.supp'}
    204 if get_option('b_sanitize') != 'none'
    205     test_env += {'PAIVANA_TEST_SCALE': '20', 'PAIVANA_SANITIZED': '1'}
    206 endif
    207 
    208 test(
    209     'reverse_proxy',
    210     files('test_reverse_proxy.sh'),
    211     env: test_env,
    212     depends: test_deps,
    213     timeout: 600,
    214 )
    215 
    216 # The paywall against a real merchant backend.  Skips (77) unless the
    217 # GNU Taler stack and PostgreSQL are there, since nothing in a bare
    218 # paivana checkout can bring an exchange and a merchant up.  Given a
    219 # long timeout because it withdraws coins and makes a payment: the
    220 # wallet's withdrawal alone is tens of seconds.
    221 test(
    222     'paywall',
    223     files('test_paywall.sh'),
    224     env: test_env,
    225     depends: test_deps,
    226     timeout: 900,
    227 )
    228 
    229 # What the reverse proxy costs: N curl clients at a fixed-size static
    230 # page, first straight at upstream_rs and then through paivana in front
    231 # of it.  Registered with benchmark() rather than test() deliberately --
    232 # `meson test' does not run benchmarks, so this stays out of
    233 # `make check', where a timing run would contribute nothing but twenty
    234 # seconds and a result that depends on how loaded the machine is.  Run
    235 # it with `meson test --benchmark proxy_overhead -C build', or call the
    236 # script directly for the options (-c clients, -s size, -d seconds).
    237 benchmark(
    238     'proxy_overhead',
    239     files('benchmark.sh'),
    240     env: test_env,
    241     depends: test_deps,
    242     timeout: 300,
    243 )
    244 
    245 # The other half of the same script: what paivana costs when it answers
    246 # by itself, i.e. the 402 paywall page an unpaid client is sent to, with
    247 # no upstream in the path.  A second entry rather than `-m all' on the
    248 # one above so that the two skip independently -- this arm needs the
    249 # generated paywall template and merchant_stub, and neither should be
    250 # able to take the proxy measurement down with it.  Its own port base
    251 # because these two would otherwise collide if anyone ran the benchmarks
    252 # in parallel, which is not meson's default but is one flag away.
    253 benchmark(
    254     'paywall_page',
    255     files('benchmark.sh'),
    256     args: ['-m', 'paywall', '-b', '18610'],
    257     env: test_env,
    258     depends: test_deps,
    259     timeout: 300,
    260 )