11BEGIN ;
2-
3- SET search_path TO keyhippo, keyhippo_rbac, public;
4-
2+ SET search_path TO keyhippo, keyhippo_rbac, public, auth;
53-- Create test users and set up authentication
64DO $$
75DECLARE
8- user1_id uuid := gen_random_uuid();
9- user2_id uuid := gen_random_uuid();
6+ user1_id uuid := gen_random_uuid ();
7+ user2_id uuid := gen_random_uuid ();
108 admin_group_id uuid;
119 admin_role_id uuid;
1210BEGIN
1311 -- Insert users with explicit IDs
1412 INSERT INTO auth .users (id, email)
15- VALUES (user1_id, ' benchuser1@example.com' ),
16- (user2_id, ' benchuser2@example.com' );
17-
13+ VALUES (user1_id, ' user1@example.com' ),
14+ (user2_id, ' user2@example.com' );
1815 -- Store user IDs as settings for later use
19- PERFORM set_config(' bench.user1_id' , user1_id::text , TRUE);
20- PERFORM set_config(' bench.user2_id' , user2_id::text , TRUE);
21-
16+ PERFORM
17+ set_config(' test.user1_id' , user1_id::text , TRUE);
18+ PERFORM
19+ set_config(' test.user2_id' , user2_id::text , TRUE);
20+ -- Initialize KeyHippo (this creates default groups and roles)
21+ PERFORM
22+ keyhippo .initialize_keyhippo ();
2223 -- Get the Admin Group and Role IDs
23- SELECT id INTO admin_group_id
24- FROM keyhippo_rbac .groups
25- WHERE name = ' Admin Group' ;
26-
27- SELECT id INTO admin_role_id
28- FROM keyhippo_rbac .roles
29- WHERE name = ' Admin' AND group_id = admin_group_id;
30-
24+ SELECT
25+ id INTO admin_group_id
26+ FROM
27+ keyhippo_rbac .groups
28+ WHERE
29+ name = ' Admin Group' ;
30+ SELECT
31+ id INTO admin_role_id
32+ FROM
33+ keyhippo_rbac .roles
34+ WHERE
35+ name = ' Admin'
36+ AND group_id = admin_group_id;
3137 -- Assign admin role to user1
3238 INSERT INTO keyhippo_rbac .user_group_roles (user_id, group_id, role_id)
33- VALUES (user1_id, admin_group_id, admin_role_id)
34- ON CONFLICT (user_id, group_id, role_id) DO NOTHING;
35-
39+ VALUES (user1_id, admin_group_id, admin_role_id)
40+ ON CONFLICT (user_id, group_id, role_id)
41+ DO NOTHING;
3642 -- Set up authentication for user1
37- PERFORM set_config(' request.jwt.claim.sub' , user1_id::text , TRUE);
38- PERFORM set_config(' request.jwt.claims' ,
39- json_build_object(' sub' , user1_id, ' role' , ' authenticated' , ' user_role' , ' admin' )::text , TRUE);
43+ PERFORM
44+ set_config(' request.jwt.claim.sub' , user1_id::text , TRUE);
45+ PERFORM
46+ set_config(' request.jwt.claims' , json_build_object(' sub' , user1_id, ' role' , ' authenticated' , ' user_role' , ' admin' )::text , TRUE);
4047END
4148$$;
42-
4349-- Function to calculate performance statistics
44- CREATE OR REPLACE FUNCTION calculate_performance_stats (execution_times double precision [])
50+ CREATE OR REPLACE FUNCTION calculate_performance_stats (execution_times double precision [])
4551 RETURNS jsonb
4652 AS $$
4753DECLARE
4854 stats jsonb;
4955 p99_time double precision ;
5056BEGIN
51- SELECT percentile_cont(0 .99 ) WITHIN GROUP (ORDER BY t) INTO p99_time
52- FROM unnest(execution_times) t;
53-
54- SELECT jsonb_build_object(
55- ' min_time' , MIN (t),
56- ' max_time' , MAX (t),
57- ' avg_time' , AVG (t),
58- ' median_time' , percentile_cont(0 .5 ) WITHIN GROUP (ORDER BY t),
59- ' stddev_time' , stddev(t),
60- ' percentile_90' , percentile_cont(0 .9 ) WITHIN GROUP (ORDER BY t),
61- ' percentile_95' , percentile_cont(0 .95 ) WITHIN GROUP (ORDER BY t),
62- ' percentile_99' , p99_time,
63- ' p99_ops_per_second' , CASE WHEN p99_time > 0 THEN 1 / p99_time ELSE 0 END
64- ) INTO stats
65- FROM unnest(execution_times) t;
66-
57+ SELECT
58+ percentile_cont(0 .99 ) WITHIN GROUP (ORDER BY t) INTO p99_time
59+ FROM
60+ unnest(execution_times) t;
61+ SELECT
62+ jsonb_build_object(' min_time' , MIN (t), ' max_time' , MAX (t), ' avg_time' , AVG (t), ' median_time' , percentile_cont(0 .5 ) WITHIN GROUP (ORDER BY t), ' stddev_time' , stddev(t), ' percentile_90' , percentile_cont(0 .9 ) WITHIN GROUP (ORDER BY t), ' percentile_95' , percentile_cont(0 .95 ) WITHIN GROUP (ORDER BY t), ' percentile_99' , p99_time, ' p99_ops_per_second' , 1 / p99_time) INTO stats
63+ FROM
64+ unnest(execution_times) t;
6765 RETURN stats;
68- END;
66+ END;
6967$$
7068LANGUAGE plpgsql;
71-
7269-- Performance test function
73- CREATE OR REPLACE FUNCTION run_performance_test (iterations integer DEFAULT 1000 )
70+ CREATE OR REPLACE FUNCTION run_performance_test (iterations integer DEFAULT 1000 )
7471 RETURNS jsonb
7572 AS $$
7673DECLARE
7774 start_time timestamp ;
7875 end_time timestamp ;
79- user_id uuid := current_setting(' bench .user1_id' )::uuid;
76+ user_id uuid := current_setting(' test .user1_id' )::uuid;
8077 created_api_key text ;
8178 execution_times double precision [];
8279 i integer ;
@@ -85,140 +82,87 @@ DECLARE
8582 test_scope_id uuid;
8683 results jsonb := ' {}' ::jsonb;
8784BEGIN
88- -- Switch to authenticated role for testing
89- SET ROLE authenticated;
90-
9185 -- Test 1: RBAC authorization
92- execution_times := ARRAY[]::double precision [];
9386 FOR i IN 1 ..iterations LOOP
9487 start_time := clock_timestamp();
95- PERFORM keyhippo .authorize (' manage_groups' );
88+ PERFORM
89+ keyhippo .authorize (' manage_groups' );
9690 end_time := clock_timestamp();
9791 execution_times := array_append(execution_times, EXTRACT(EPOCH FROM (end_time - start_time)));
9892 END LOOP;
99- results := results || jsonb_build_object(' RBAC authorization' , calculate_performance_stats(execution_times));
100-
101- -- Test 2: Current user context
93+ results := results || jsonb_build_object(' RBAC authorization' , calculate_performance_stats (execution_times));
94+ -- Test 2: Create group
10295 execution_times := ARRAY[]::double precision [];
10396 FOR i IN 1 ..iterations LOOP
10497 start_time := clock_timestamp();
105- PERFORM keyhippo .current_user_context ();
106- end_time := clock_timestamp();
107- execution_times := array_append(execution_times, EXTRACT(EPOCH FROM (end_time - start_time)));
108- END LOOP;
109- results := results || jsonb_build_object(' Current user context' , calculate_performance_stats(execution_times));
110-
111- -- Test 3: Create group
112- execution_times := ARRAY[]::double precision [];
113- FOR i IN 1 ..LEAST(iterations, 100 ) LOOP -- Limit to avoid too many groups
114- start_time := clock_timestamp();
115- SELECT keyhippo_rbac .create_group (' Bench Group ' || i::text , ' Benchmark group' ) INTO test_group_id;
116- end_time := clock_timestamp();
117- execution_times := array_append(execution_times, EXTRACT(EPOCH FROM (end_time - start_time)));
118- END LOOP;
119- results := results || jsonb_build_object(' Create group' , calculate_performance_stats(execution_times));
120-
121- -- Test 4: Create role
122- execution_times := ARRAY[]::double precision [];
123- FOR i IN 1 ..LEAST(iterations, 100 ) LOOP -- Limit to avoid too many roles
124- start_time := clock_timestamp();
125- SELECT keyhippo_rbac .create_role (' Bench Role ' || i::text , ' Benchmark role' , test_group_id, ' user' ::keyhippo .app_role ) INTO test_role_id;
98+ SELECT
99+ keyhippo_rbac .create_group (' Test Group ' || i::text , ' Test group description' ) INTO test_group_id;
126100 end_time := clock_timestamp();
127101 execution_times := array_append(execution_times, EXTRACT(EPOCH FROM (end_time - start_time)));
128102 END LOOP;
129- results := results || jsonb_build_object(' Create role' , calculate_performance_stats(execution_times));
130-
131- -- Test 5: Assign role to user
103+ results := results || jsonb_build_object(' Create group' , calculate_performance_stats (execution_times));
104+ -- Test 3: Create role
132105 execution_times := ARRAY[]::double precision [];
133106 FOR i IN 1 ..iterations LOOP
134107 start_time := clock_timestamp();
135- PERFORM keyhippo_rbac .assign_role_to_user (user_id, test_group_id, test_role_id);
108+ SELECT
109+ keyhippo_rbac .create_role (' Test Role ' || i::text , ' Test role description' , test_group_id, ' user' ::keyhippo .app_role ) INTO test_role_id;
136110 end_time := clock_timestamp();
137111 execution_times := array_append(execution_times, EXTRACT(EPOCH FROM (end_time - start_time)));
138112 END LOOP;
139- results := results || jsonb_build_object(' Assign role to user' , calculate_performance_stats(execution_times));
140-
141- -- Test 6: API key creation
113+ results := results || jsonb_build_object(' Create role' , calculate_performance_stats (execution_times));
114+ -- Test 4: Assign role to user
142115 execution_times := ARRAY[]::double precision [];
143- FOR i IN 1 ..LEAST( iterations, 100 ) LOOP -- Limit to avoid too many keys
116+ FOR i IN 1 ..iterations LOOP
144117 start_time := clock_timestamp();
145- SELECT api_key INTO created_api_key
146- FROM keyhippo . create_api_key ( ' Bench Key ' || i:: text );
118+ PERFORM
119+ keyhippo_rbac . assign_role_to_user (user_id, test_group_id, test_role_id );
147120 end_time := clock_timestamp();
148121 execution_times := array_append(execution_times, EXTRACT(EPOCH FROM (end_time - start_time)));
149122 END LOOP;
150- results := results || jsonb_build_object(' API key creation' , calculate_performance_stats(execution_times));
151-
152- -- Test 7: API key verification
123+ results := results || jsonb_build_object(' Assign role to user' , calculate_performance_stats (execution_times));
124+ -- Test 5: API key creation
153125 execution_times := ARRAY[]::double precision [];
154126 FOR i IN 1 ..iterations LOOP
155127 start_time := clock_timestamp();
156- PERFORM keyhippo .verify_api_key (created_api_key);
128+ SELECT
129+ api_key INTO created_api_key
130+ FROM
131+ keyhippo .create_api_key (' Performance Test Key ' || i::text );
157132 end_time := clock_timestamp();
158133 execution_times := array_append(execution_times, EXTRACT(EPOCH FROM (end_time - start_time)));
159134 END LOOP;
160- results := results || jsonb_build_object(' API key verification' , calculate_performance_stats(execution_times));
161-
162- -- Test 8: Create scope
135+ results := results || jsonb_build_object(' API key creation' , calculate_performance_stats (execution_times));
136+ -- Test 6: API key verification
163137 execution_times := ARRAY[]::double precision [];
164- FOR i IN 1 ..LEAST( iterations, 100 ) LOOP -- Limit to avoid too many scopes
138+ FOR i IN 1 ..iterations LOOP
165139 start_time := clock_timestamp();
166- INSERT INTO keyhippo .scopes (name, description)
167- VALUES (' bench_scope_' || i::text , ' Benchmark scope' )
168- RETURNING id INTO test_scope_id;
140+ PERFORM
141+ keyhippo .verify_api_key (created_api_key);
169142 end_time := clock_timestamp();
170143 execution_times := array_append(execution_times, EXTRACT(EPOCH FROM (end_time - start_time)));
171144 END LOOP;
172- results := results || jsonb_build_object(' Create scope' , calculate_performance_stats(execution_times));
173-
174- -- Test 9: Key data retrieval
145+ results := results || jsonb_build_object(' API key verification' , calculate_performance_stats (execution_times));
146+ -- Test 7: Create scope
175147 execution_times := ARRAY[]::double precision [];
176148 FOR i IN 1 ..iterations LOOP
177149 start_time := clock_timestamp();
178- PERFORM keyhippo .key_data ();
150+ INSERT INTO keyhippo .scopes (name, description)
151+ VALUES (' test_scope_' || i::text , ' Test scope description' )
152+ RETURNING
153+ id INTO test_scope_id;
179154 end_time := clock_timestamp();
180155 execution_times := array_append(execution_times, EXTRACT(EPOCH FROM (end_time - start_time)));
181156 END LOOP;
182- results := results || jsonb_build_object(' Key data retrieval' , calculate_performance_stats(execution_times));
183-
157+ results := results || jsonb_build_object(' Create scope' , calculate_performance_stats (execution_times));
184158 RETURN results;
185159END;
186160$$
187161LANGUAGE plpgsql;
188-
189- -- Run performance tests and display results
190- DO $$
191- DECLARE
192- test_results jsonb;
193- test_name text ;
194- test_stats jsonb;
195- BEGIN
196- RAISE NOTICE ' Starting performance benchmark with 1000 iterations...' ;
197- RAISE NOTICE ' ' ;
198-
199- SELECT run_performance_test(1000 ) INTO test_results;
200-
201- -- Display results in a formatted way
202- FOR test_name, test_stats IN SELECT * FROM jsonb_each(test_results) LOOP
203- RAISE NOTICE ' === % ===' , test_name;
204- RAISE NOTICE ' Min time: % ms' , ROUND((test_stats- >> ' min_time' )::numeric * 1000 , 3 );
205- RAISE NOTICE ' Max time: % ms' , ROUND((test_stats- >> ' max_time' )::numeric * 1000 , 3 );
206- RAISE NOTICE ' Avg time: % ms' , ROUND((test_stats- >> ' avg_time' )::numeric * 1000 , 3 );
207- RAISE NOTICE ' Median time: % ms' , ROUND((test_stats- >> ' median_time' )::numeric * 1000 , 3 );
208- RAISE NOTICE ' 90th percentile: % ms' , ROUND((test_stats- >> ' percentile_90' )::numeric * 1000 , 3 );
209- RAISE NOTICE ' 95th percentile: % ms' , ROUND((test_stats- >> ' percentile_95' )::numeric * 1000 , 3 );
210- RAISE NOTICE ' 99th percentile: % ms' , ROUND((test_stats- >> ' percentile_99' )::numeric * 1000 , 3 );
211- RAISE NOTICE ' P99 ops/sec: %' , ROUND((test_stats- >> ' p99_ops_per_second' )::numeric , 0 );
212- RAISE NOTICE ' ' ;
213- END LOOP;
214-
215- RAISE NOTICE ' Benchmark completed successfully!' ;
216- END
217- $$;
218-
219- -- Clean up benchmark functions (switch to postgres role for cleanup)
220- SET ROLE postgres;
221- DROP FUNCTION run_performance_test(integer );
222- DROP FUNCTION calculate_performance_stats(double precision []);
223-
162+ -- Run performance tests and display results as JSON
163+ SELECT
164+ run_performance_test (10000 )::text AS performance_results;
165+ -- Clean up
166+ DROP FUNCTION run_performance_test (integer );
167+ DROP FUNCTION calculate_performance_stats (double precision []);
224168ROLLBACK ;
0 commit comments