Skip to content

Commit 9aa69bd

Browse files
committed
new tests
1 parent 5af60bf commit 9aa69bd

149 files changed

Lines changed: 1504 additions & 2610 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -433,3 +433,6 @@ build/
433433

434434
*.sln
435435
pg_function_load_tests.sln
436+
437+
.DS_Store
438+
Thumbs.db

src/.env

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
BUILDX_NO_DEFAULT_ATTESTATIONS=1

src/_k6/scripts/run.sh

Lines changed: 21 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -7,44 +7,32 @@ mkdir -p /results/$STAMP
77

88
echo "*** Starting k6 tests, output will be saved in /results/$STAMP"
99

10-
for records in 1 10 100 500; do # records retrieved
11-
for target in 1 50 100; do # target number of virtual users VUs
12-
for duration in 60s; do # 10s 60s 120s; do # for duration in 5s 60s 120s; do # duration of the test
10+
# for records in 1 10 100 500; do # records retrieved
11+
# for target in 1 50 100; do # target number of virtual users VUs
12+
# for duration in 60s; do # duration of the test
13+
for records in 10; do # records retrieved
14+
for target in 1; do # target number of virtual users VUs
15+
for duration in 5s; do # duration of the test
1316
while read -r tag port; do
1417
echo "*** Running $tag:$port with $records records, $target VUs, and $duration duration"
1518
k6 run /scripts/script.js -e STAMP=$STAMP -e TAG=$tag -e PORT=$port -e RECORDS=$records -e DURATION=$duration -e TARGET=$target
1619
sleep 10 # sleep for 10 seconds between tests
1720
done << EOF
18-
django-app-v5.0.9 8000
19-
express-app-v4.18.2 3100
20-
postgrest-v12.2.3 3000
21-
fastapi-app-v0.103.2 8001
22-
fastify-app-v4.26.1 3101
23-
deno-app-v1.40.2 3102
24-
swoole-php-app-8.3.13 3103
25-
npgsqlrest-aot-v2.2.1 5000
26-
net8-npgsqlrest-jit-v2.12.1 5001
27-
net8-minapi-ef-jit-v8.0.10 5002
28-
net8-minapi-dapper-jit-v2.1.35 5003
29-
net8-minapi-norm-jit-v5.4.0 5004
30-
net8-minapi-ado-jit-v8.0.5 5005
31-
go-app-v1.22.9 5200
32-
rust-app-v1.75.0 5300
33-
java21-spring-boot-v3.2.2 5400
34-
perl-net-server-prefork-v5.34 8088
35-
npgsqlrest-aot-v2.4.0 5500
36-
npgsqlrest-aot-v2.5.0 5506
37-
npgsqlrest-aot-v2.6.0 5508
38-
npgsqlrest-aot-v2.7.0 5510
39-
net9-npgsqlrest-jit-v2.13.1 5501
40-
net9-npgsqlrest-jit-v2.14.0 5507
41-
net9-npgsqlrest-jit-v2.15.0 5509
42-
net9-npgsqlrest-jit-v2.16.0 5511
43-
net9-minapi-ef-jit-v9.0.1 5502
44-
net9-minapi-dapper-jit-v2.1.35 5503
45-
net9-minapi-norm-jit-v5.4.0 5504
46-
net9-minapi-ado-jit-v8.0.5 5505
47-
omnigres-master 8080
21+
django-app-v5.1.4 8000
22+
fastapi-app-v0.115.6 8001
23+
fastify-app-v5.2.1 3101
24+
bun-app-v1.1.42 3104
25+
go-app-v1.23.4 5200
26+
java24-spring-boot-v3.4.1 5400
27+
rust-app-v1.83.0 5300
28+
swoole-php-app-v8.4.0 3103
29+
postgrest-v12.2.8 3000
30+
net9-minapi-ef-jit 5002
31+
net10-minapi-ef-jit 5003
32+
net10-minapi-dapper-jit 5004
33+
npgsqlrest-aot-v2.36.2 5000
34+
npgsqlrest-aot-v3.2.2 5001
35+
npgsqlrest-jit-v3.2.2 5005
4836
EOF
4937
done # duration of the test
5038
done # target number of virtual users VUs

src/_k6/scripts/script.js

Lines changed: 60 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,60 @@ const records = Number(__ENV.RECORDS.trim() || "10")
88
const duration = __ENV.DURATION.trim() || "60s";
99
const target = Number(__ENV.TARGET.trim() || "100");
1010
const port = __ENV.PORT.trim();
11-
const path = __ENV.REQ_PATH ? __ENV.REQ_PATH.trim() : (tag.indexOf('postgrest') != -1 ? '/rpc/test_func_v1' : '/api/test-data');
12-
13-
const url = 'http://' + tag + ':' + port + path + "?" +
14-
Object.entries({
15-
_records: records,
16-
_text_param: 'ABCDEFGHIJKLMNOPRSTUVWXYZ',
17-
_int_param: 1234567890,
18-
_ts_param: new Date('2014-12-31').toISOString(),
19-
_bool_param: true
20-
})
11+
12+
// Determine the path based on the service type
13+
function getPath(tag) {
14+
if (tag.indexOf('postgrest') !== -1) {
15+
return '/rpc/perf_test';
16+
}
17+
return '/api/perf-test';
18+
}
19+
20+
// Check if this service uses repeated query params for arrays (like ?a=1&a=2&a=3)
21+
// .NET minimal API and NpgsqlRest bind arrays this way
22+
function usesRepeatedQueryParams(tag) {
23+
return tag.indexOf('npgsqlrest') !== -1 ||
24+
tag.indexOf('net9-minapi') !== -1 ||
25+
tag.indexOf('net10-minapi') !== -1;
26+
}
27+
28+
const path = __ENV.REQ_PATH ? __ENV.REQ_PATH.trim() : getPath(tag);
29+
30+
// Base parameters (non-array)
31+
const baseParams = {
32+
_records: records,
33+
_text: 'ABCDEFGHIJKLMNOPRSTUVWXYZ',
34+
_int: 1234567890,
35+
_bigint: '9223372036854770000',
36+
_numeric: '12345.6789',
37+
_real: '123.45',
38+
_double: '123456.789012',
39+
_bool: true,
40+
_date: '2024-01-15',
41+
_timestamp: '2024-01-15T10:30:00',
42+
_timestamptz: '2024-01-15T10:30:00Z',
43+
_uuid: 'a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11',
44+
_json: '{"key":"value"}',
45+
_jsonb: '{"key":"value"}'
46+
};
47+
48+
// Build URL with all test parameters
49+
// NpgsqlRest uses repeated query params for arrays: _int_array=1&_int_array=2&_int_array=3
50+
// Other services use PostgreSQL array literal: _int_array={1,2,3}
51+
let baseUrl = 'http://' + tag + ':' + port + path + '?' +
52+
Object.entries(baseParams)
2153
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
2254
.join('&');
2355

56+
let url;
57+
if (usesRepeatedQueryParams(tag)) {
58+
// .NET services and NpgsqlRest: use repeated query params for arrays
59+
url = baseUrl + '&_int_array=1&_int_array=2&_int_array=3&_text_array=a&_text_array=b&_text_array=c';
60+
} else {
61+
// Other services: use PostgreSQL array literal format
62+
url = baseUrl + '&_int_array=' + encodeURIComponent('{1,2,3}') + '&_text_array=' + encodeURIComponent('{a,b,c}');
63+
}
64+
2465
export const options = {
2566
thresholds: {
2667
http_req_failed: [{ threshold: "rate<0.01", abortOnFail: true }], // availability threshold for error rate
@@ -42,9 +83,16 @@ export default function () {
4283
[`${tag} status is 200`]: (r) => r.status === 200,
4384
[`${tag} response is JSON`]: (r) => r.headers['Content-Type'] && r.headers['Content-Type'].includes('application/json'),
4485
[`${tag} response has all data records`]: (r) => r.body && JSON.parse(r.body).length == records,
45-
[`${tag} response first item has all fields`]: (r) => {
86+
[`${tag} response first item has expected fields`]: (r) => {
4687
let d = JSON.parse(r.body)[0];
47-
return d.id1 && d.foo1 && d.bar1 && d.datetime1 && d.id2 && d.foo2 && d.bar2 && d.datetime2 && d.long_foo_bar && d.is_foobar;
88+
return d.row_num !== undefined &&
89+
d.text_val !== undefined &&
90+
d.varchar_val !== undefined &&
91+
d.int_val !== undefined &&
92+
d.bigint_val !== undefined &&
93+
d.bool_val !== undefined &&
94+
d.date_val !== undefined &&
95+
d.uuid_val !== undefined;
4896
}
4997
});
5098
}
@@ -57,7 +105,6 @@ export function handleSummary(data) {
57105
const failedReqs = data.metrics.http_req_failed.values.passes;
58106
return {
59107
[`/results/${stamp}/${fileTag}_summary.txt`]: textSummary(data, { indent: ' ', enableColors: false }),
60-
//[`/results/${stamp}/${fileTag}_summary.json`]: JSON.stringify(data, null, 2),
61108
[`/results/${stamp}/${fileTag}.md`]: `|${tag}|${target}|${duration}|${records}|${reqs}|${reqsPerSec}|${reqsDuration}|${failedReqs}|[summary](/${stamp}/${fileTag}_summary.txt)|`,
62109
}
63110
}

src/_postgres/init.sql

Lines changed: 85 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,98 @@
1-
create function public.test_func_v1(
1+
create extension if not exists "uuid-ossp";
2+
3+
-- Main performance test function with all parameter types
4+
create function public.perf_test(
25
_records int,
3-
_text_param text,
4-
_int_param int,
5-
_ts_param timestamp,
6-
_bool_param bool
7-
)
6+
_text text,
7+
_int int,
8+
_bigint bigint,
9+
_numeric numeric,
10+
_real real,
11+
_double double precision,
12+
_bool bool,
13+
_date date,
14+
_timestamp timestamp,
15+
_timestamptz timestamptz,
16+
_uuid uuid,
17+
_json json,
18+
_jsonb jsonb,
19+
_int_array int[],
20+
_text_array text[]
21+
)
822
returns table(
9-
id1 int,
10-
foo1 text,
11-
bar1 text,
12-
datetime1 timestamp,
13-
id2 int,
14-
foo2 text,
15-
bar2 text,
16-
datetime2 timestamp,
17-
long_foo_bar text,
18-
is_foobar bool
23+
row_num int,
24+
-- text types
25+
text_val text,
26+
varchar_val varchar(100),
27+
char_val char(10),
28+
-- integer types
29+
smallint_val smallint,
30+
int_val int,
31+
bigint_val bigint,
32+
-- floating point
33+
numeric_val numeric(12,4),
34+
real_val real,
35+
double_val double precision,
36+
-- boolean
37+
bool_val bool,
38+
-- date/time
39+
date_val date,
40+
time_val time,
41+
timestamp_val timestamp,
42+
timestamptz_val timestamptz,
43+
interval_val interval,
44+
-- special types
45+
uuid_val uuid,
46+
json_val json,
47+
jsonb_val jsonb,
48+
-- arrays
49+
int_array_val int[],
50+
text_array_val text[],
51+
-- nullable
52+
nullable_text text,
53+
nullable_int int
1954
)
2055
stable
2156
language sql
2257
as
2358
$$
2459
select
25-
i + _int_param as id1,
26-
'foo' || '_' || _text_param || '_' || i::text as foo1,
27-
'bar' || i::text as bar1,
28-
(_ts_param::date) + (i::text || ' days')::interval as datetime1,
29-
i+1 + _int_param as id2,
30-
'foo' || '_' || _text_param || '_' || (i+1)::text as foo2,
31-
'bar' || '_' || _text_param || '_' || (i+1)::text as bar2,
32-
(_ts_param::date) + ((i+1)::text || ' days')::interval as datetime2,
33-
'long_foo_bar_' || '_' || _text_param || '_' || (i+2)::text as long_foo_bar,
34-
(i % 2)::boolean and _bool_param as is_foobar
60+
i as row_num,
61+
-- text types
62+
_text || '_' || i::text as text_val,
63+
left(_text || '_' || i::text, 100)::varchar(100) as varchar_val,
64+
lpad(i::text, 10, '0')::char(10) as char_val,
65+
-- integer types
66+
(i % 32767)::smallint as smallint_val,
67+
_int + i as int_val,
68+
_bigint + i as bigint_val,
69+
-- floating point
70+
(_numeric + i + 0.1234)::numeric(12,4) as numeric_val,
71+
(_real + i * 0.1)::real as real_val,
72+
(_double + i * 0.001)::double precision as double_val,
73+
-- boolean
74+
case when i % 2 = 0 then _bool else not _bool end as bool_val,
75+
-- date/time
76+
_date + i as date_val,
77+
('12:00:00'::time + (i || ' minutes')::interval)::time as time_val,
78+
_timestamp + (i || ' hours')::interval as timestamp_val,
79+
_timestamptz + (i || ' hours')::interval as timestamptz_val,
80+
(i || ' days')::interval as interval_val,
81+
-- special types
82+
case when i = 1 then _uuid
83+
else uuid_generate_v5(_uuid, i::text) end as uuid_val,
84+
(_json::jsonb || jsonb_build_object('i', i))::json as json_val,
85+
_jsonb || jsonb_build_object('row', i) as jsonb_val,
86+
-- arrays
87+
_int_array || array[i] as int_array_val,
88+
_text_array || array[_text || i::text] as text_array_val,
89+
-- nullable (nulls on even rows)
90+
case when i % 2 = 1 then _text || '_' || i::text else null end as nullable_text,
91+
case when i % 2 = 1 then i else null end as nullable_int
3592
from
3693
generate_series(1, _records) as i
3794
$$;
3895

39-
comment on function public.test_func_v1(int, text, int, timestamp, bool) is 'HTTP GET /api/test-data';
96+
comment on function public.perf_test(int,text,int,bigint,numeric,real,double precision,bool,date,timestamp,timestamptz,uuid,json,jsonb,int[],text[]) is 'HTTP GET /api/perf-test';
4097

41-
show max_connections;
98+
show max_connections;

src/bun-app-v1.1.42/Dockerfile

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
FROM oven/bun:1.1.42
2+
3+
WORKDIR /app
4+
COPY package.json ./
5+
RUN bun install --production
6+
COPY . .
7+
8+
EXPOSE 3104
9+
10+
CMD ["bun", "run", "app.ts"]

src/bun-app-v1.1.42/app.ts

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import postgres from 'postgres';
2+
3+
const sql = postgres({
4+
host: process.env.DB_HOST || 'postgres',
5+
port: 5432,
6+
database: process.env.DB_NAME || 'testdb',
7+
username: process.env.DB_USER || 'testuser',
8+
password: process.env.DB_PASSWORD || 'testpass',
9+
max: 100
10+
});
11+
12+
const server = Bun.serve({
13+
port: 3104,
14+
async fetch(request) {
15+
// Extract path and query from request.url manually to avoid URL parsing issues with Docker hostnames
16+
const rawUrl = request.url;
17+
const pathStart = rawUrl.indexOf('/', rawUrl.indexOf('://') + 3);
18+
const pathAndQuery = pathStart >= 0 ? rawUrl.substring(pathStart) : '/';
19+
const [pathname, queryString] = pathAndQuery.split('?');
20+
const params = new URLSearchParams(queryString || '');
21+
22+
if (pathname === '/api/perf-test' && request.method === 'GET') {
23+
const records = parseInt(params.get('_records') || '0');
24+
const text = params.get('_text') || '';
25+
const intVal = parseInt(params.get('_int') || '0');
26+
const bigint = params.get('_bigint') || '0';
27+
const numeric = params.get('_numeric') || '0';
28+
const real = params.get('_real') || '0';
29+
const double = params.get('_double') || '0';
30+
const bool = params.get('_bool') === 'true';
31+
const date = params.get('_date') || '';
32+
const timestamp = params.get('_timestamp') || '';
33+
const timestamptz = params.get('_timestamptz') || '';
34+
const uuid = params.get('_uuid') || '';
35+
const json = params.get('_json') || '{}';
36+
const jsonb = params.get('_jsonb') || '{}';
37+
const intArray = params.get('_int_array') || '{}';
38+
const textArray = params.get('_text_array') || '{}';
39+
40+
const rows = await sql`
41+
SELECT row_num, text_val, varchar_val, char_val, smallint_val, int_val, bigint_val,
42+
numeric_val, real_val, double_val, bool_val, date_val, time_val,
43+
timestamp_val, timestamptz_val, interval_val, uuid_val, json_val, jsonb_val,
44+
int_array_val, text_array_val, nullable_text, nullable_int
45+
FROM public.perf_test(${records}, ${text}, ${intVal}, ${bigint}::bigint, ${numeric}::numeric, ${real}::real, ${double}::double precision, ${bool}, ${date}::date, ${timestamp}::timestamp, ${timestamptz}::timestamptz, ${uuid}::uuid, ${json}::json, ${jsonb}::jsonb, ${intArray}::int[], ${textArray}::text[])
46+
`;
47+
48+
return new Response(JSON.stringify(rows), {
49+
headers: { 'Content-Type': 'application/json' }
50+
});
51+
}
52+
53+
return new Response('Not Found', { status: 404 });
54+
}
55+
});
56+
57+
console.log(`Bun server running on port ${server.port}`);

src/bun-app-v1.1.42/package.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"name": "bun-test-app",
3+
"type": "module",
4+
"dependencies": {
5+
"postgres": "3.4.5"
6+
}
7+
}

src/deno-app-v1.40.2/Dockerfile

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)