From 0948d388631c7bf16563df6d07811d94b4a81342 Mon Sep 17 00:00:00 2001 From: Wolfgang Walther Date: Sun, 16 Jun 2024 17:34:01 +0200 Subject: [PATCH] test: Rewrite JWT cache tests Timing dependent tests in the IO tests don't work too well when the next commit increases the JWT parsing performance. The remaining IO tests are for coverage and basic breakage. Loadtests are adapted so that performance regressions for JWT caching would be detected that way. --- nix/tools/loadtest.nix | 2 + test/io/test_io.py | 104 ++++++++++++++--------------------------- test/load/targets.http | 6 +++ 3 files changed, 42 insertions(+), 70 deletions(-) diff --git a/nix/tools/loadtest.nix b/nix/tools/loadtest.nix index 5aaf5c913..79347bacb 100644 --- a/nix/tools/loadtest.nix +++ b/nix/tools/loadtest.nix @@ -55,6 +55,8 @@ let export PGRST_DB_POOL="1" export PGRST_DB_TX_END="rollback-allow-override" export PGRST_LOG_LEVEL="crit" + export PGRST_JWT_SECRET="reallyreallyreallyreallyverysafe" + export PGRST_JWT_CACHE_MAX_LIFETIME="86400" mkdir -p "$(dirname "$_arg_output")" abs_output="$(realpath "$_arg_output")" diff --git a/test/io/test_io.py b/test/io/test_io.py index 1fb52118a..f71e1594d 100644 --- a/test/io/test_io.py +++ b/test/io/test_io.py @@ -1310,14 +1310,14 @@ def test_fail_with_automatic_recovery_disabled_and_terminated_using_query(defaul assert exitCode == 1 -def test_server_timing_jwt_should_decrease_on_subsequent_requests(defaultenv): - "assert that server-timing duration for JWT should decrease on subsequent requests" +def test_jwt_cache_server_timing(defaultenv): + "server-timing duration is exposed for JWT with expiry" env = { **defaultenv, "PGRST_SERVER_TIMING_ENABLED": "true", "PGRST_JWT_CACHE_MAX_LIFETIME": "86400", - "PGRST_JWT_SECRET": "@/dev/stdin", + "PGRST_JWT_SECRET": SECRET, "PGRST_DB_CONFIG": "false", } @@ -1331,102 +1331,66 @@ def test_server_timing_jwt_should_decrease_on_subsequent_requests(defaultenv): SECRET, ) - with run(stdin=SECRET.encode(), env=env) as postgrest: - first_timings = postgrest.session.get("/authors_only", headers=headers).headers[ - "Server-Timing" - ] - second_timings = postgrest.session.get( - "/authors_only", headers=headers - ).headers["Server-Timing"] + with run(env=env) as postgrest: + first = postgrest.session.get("/authors_only", headers=headers) + second = postgrest.session.get("/authors_only", headers=headers) - first_dur = parse_server_timings_header(first_timings)["jwt"] - second_dur = parse_server_timings_header(second_timings)["jwt"] + assert first.status_code == 200 + assert second.status_code == 200 - # their difference should be atleast 0.3ms, implying - # that JWT Caching is working as expected - assert (first_dur - second_dur) > 0.3 + first_dur = parse_server_timings_header(first.headers["Server-Timing"])["jwt"] + second_dur = parse_server_timings_header(second.headers["Server-Timing"])["jwt"] + + assert first_dur >= 0 + assert second_dur >= 0 -# just added to complete code coverage -def test_jwt_caching_works_with_db_plan_disabled(defaultenv): - "assert that JWT caching words even when Server-Timing header is not returned" +def test_jwt_cache_without_server_timing(defaultenv): + "JWT cache does not break requests without server-timing enabled" env = { **defaultenv, "PGRST_SERVER_TIMING_ENABLED": "true", "PGRST_JWT_CACHE_MAX_LIFETIME": "86400", - "PGRST_JWT_SECRET": "@/dev/stdin", + "PGRST_JWT_SECRET": SECRET, "PGRST_DB_CONFIG": "false", } headers = jwtauthheader({"role": "postgrest_test_author"}, SECRET) - with run(stdin=SECRET.encode(), env=env) as postgrest: - first_request = postgrest.session.get("/authors_only", headers=headers) - second_request = postgrest.session.get("/authors_only", headers=headers) + with run(env=env) as postgrest: + first = postgrest.session.get("/authors_only", headers=headers) + second = postgrest.session.get("/authors_only", headers=headers) - # in this case we don't get server-timing in response headers - # so we can't compare durations, we just check if request succeeds - assert first_request.status_code == 200 and second_request.status_code == 200 + assert first.status_code == 200 + assert second.status_code == 200 -def test_server_timing_jwt_should_not_decrease_when_caching_disabled(defaultenv): - "assert than jwt duration should not decrease when disabled" - - env = { - **defaultenv, - "PGRST_SERVER_TIMING_ENABLED": "true", - "PGRST_JWT_CACHE_MAX_LIFETIME": "0", # cache disabled - "PGRST_JWT_SECRET": "@/dev/stdin", - "PGRST_DB_CONFIG": "false", - } - - headers = jwtauthheader({"role": "postgrest_test_author"}, SECRET) - - with run(stdin=SECRET.encode(), env=env) as postgrest: - warmup_req = postgrest.session.get("/authors_only", headers=headers) - first_timings = postgrest.session.get("/authors_only", headers=headers).headers[ - "Server-Timing" - ] - second_timings = postgrest.session.get( - "/authors_only", headers=headers - ).headers["Server-Timing"] - - first_dur = parse_server_timings_header(first_timings)["jwt"] - second_dur = parse_server_timings_header(second_timings)["jwt"] - - # their difference should be less than 150 - # implying that token is not cached - assert (first_dur - second_dur) < 150.0 - - -def test_jwt_cache_with_no_exp_claim(defaultenv): - "assert than jwt duration should decrease" +def test_jwt_cache_without_exp_claim(defaultenv): + "server-timing duration is exposed for JWT without expiry" env = { **defaultenv, "PGRST_SERVER_TIMING_ENABLED": "true", "PGRST_JWT_CACHE_MAX_LIFETIME": "86400", - "PGRST_JWT_SECRET": "@/dev/stdin", + "PGRST_JWT_SECRET": SECRET, "PGRST_DB_CONFIG": "false", } headers = jwtauthheader({"role": "postgrest_test_author"}, SECRET) # no exp - with run(stdin=SECRET.encode(), env=env) as postgrest: - first_timings = postgrest.session.get("/authors_only", headers=headers).headers[ - "Server-Timing" - ] - second_timings = postgrest.session.get( - "/authors_only", headers=headers - ).headers["Server-Timing"] + with run(env=env) as postgrest: + first = postgrest.session.get("/authors_only", headers=headers) + second = postgrest.session.get("/authors_only", headers=headers) - first_dur = parse_server_timings_header(first_timings)["jwt"] - second_dur = parse_server_timings_header(second_timings)["jwt"] + assert first.status_code == 200 + assert second.status_code == 200 - # their difference should be atleast 0.3ms, implying - # that JWT Caching is working as expected - assert (first_dur - second_dur) > 0.3 + first_dur = parse_server_timings_header(first.headers["Server-Timing"])["jwt"] + second_dur = parse_server_timings_header(second.headers["Server-Timing"])["jwt"] + + assert first_dur >= 0 + assert second_dur >= 0 def test_preflight_request_with_cors_allowed_origin_config(defaultenv): diff --git a/test/load/targets.http b/test/load/targets.http index ce65472a7..b77fbdae8 100644 --- a/test/load/targets.http +++ b/test/load/targets.http @@ -1,10 +1,12 @@ GET http://postgrest/ +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CUIP5V9thWsGGFsFyGijSZf1fJMfarLHI9CEJL-TGNk Prefer: tx=commit HEAD http://postgrest/actors?actor=eq.1 Prefer: tx=commit GET http://postgrest/actors?select=*,roles(*,films(*)) +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CUIP5V9thWsGGFsFyGijSZf1fJMfarLHI9CEJL-TGNk Prefer: tx=commit POST http://postgrest/films?columns=id,title @@ -12,6 +14,7 @@ Prefer: tx=rollback @post.json POST http://postgrest/films?columns=id,title,year,runtime,genres,director,actors,plot,posterUrl +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CUIP5V9thWsGGFsFyGijSZf1fJMfarLHI9CEJL-TGNk Prefer: tx=rollback # this bulk.json was obtained from https://github.com/erik-sytnyk/movies-list/blob/master/db.json @bulk.json @@ -21,6 +24,7 @@ Prefer: tx=rollback @put.json PATCH http://postgrest/actors?actor=eq.1 +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CUIP5V9thWsGGFsFyGijSZf1fJMfarLHI9CEJL-TGNk Prefer: tx=rollback @patch.json @@ -28,8 +32,10 @@ DELETE http://postgrest/roles Prefer: tx=rollback GET http://postgrest/rpc/call_me?name=John +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CUIP5V9thWsGGFsFyGijSZf1fJMfarLHI9CEJL-TGNk POST http://postgrest/rpc/call_me @rpc.json OPTIONS http://postgrest/actors +Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.e30.CUIP5V9thWsGGFsFyGijSZf1fJMfarLHI9CEJL-TGNk