test: 8 стресс-функций (py/go/js), crash-тесты, stress_test.sh — 32 строки в PG

This commit is contained in:
Naeel
2026-03-19 19:44:26 +03:00
parent d87981713d
commit 014b99ed16
16 changed files with 463 additions and 0 deletions
@@ -0,0 +1,20 @@
# 2026-03-19
# stress_bigloop.py — CPU-интенсивная функция: считает сумму квадратов N чисел.
# Проверяет поведение под нагрузкой (большая и средняя итерация).
import time
_VERSION = "v1"
def run(event):
n = int(event.get("n", 500_000))
start = time.monotonic()
total = sum(i * i for i in range(n))
elapsed = round(time.monotonic() - start, 4)
return {
"version": _VERSION,
"n": n,
"sum_of_squares": total,
"elapsed_sec": elapsed,
}
@@ -0,0 +1,13 @@
# 2026-03-19
# stress_divzero.py — намеренно делит на ноль (ZeroDivisionError).
# Проверяет: платформа перехватывает панику, возвращает HTTP 500, не роняет под.
_VERSION = "v1"
def run(event):
numerator = int(event.get("n", 42))
denominator = int(event.get("d", 0)) # по умолчанию 0 — намеренный краш
# ZeroDivisionError: проверяем что платформа обрабатывает исключения
result = numerator / denominator
return {"version": _VERSION, "result": result}
@@ -0,0 +1,47 @@
// 2026-03-19
// handler.go — быстрая Go функция: факториал + числа Фибоначчи.
// Проверяет Go runtime под лёгкой нагрузкой и корректность JSON-ответа.
//
// Entrypoint: handler.Handle
package handler
import "fmt"
// factorial — рекурсивный факториал (для небольших n <= 20).
func factorial(n int) uint64 {
if n <= 1 {
return 1
}
return uint64(n) * factorial(n-1)
}
// fib — итеративное число Фибоначчи.
func fib(n int) int {
if n <= 1 {
return n
}
a, b := 0, 1
for i := 2; i <= n; i++ {
a, b = b, a+b
}
return b
}
// Handle — точка входа рантайма.
func Handle(event map[string]interface{}) interface{} {
n := 10
if v, ok := event["n"].(float64); ok {
n = int(v)
if n > 20 {
n = 20
}
}
return map[string]interface{}{
"runtime": "go1.23",
"version": "v1",
"n": n,
"factorial": fmt.Sprintf("%d", factorial(n)),
"fib": fib(n),
}
}
@@ -0,0 +1,21 @@
// 2026-03-19
// handler.go — намеренный nil pointer dereference в Go.
// Проверяет что Go runtime recover() перехватывает панику и платформа возвращает 500.
// Entrypoint: handler.Handle
package handler
func Handle(event map[string]interface{}) interface{} {
crash := true
if v, ok := event["crash"].(bool); ok {
crash = v
}
if crash {
var p *string
_ = *p // panic: намеренный nil pointer для stress-теста
}
return map[string]interface{}{
"runtime": "go1.23",
"version": "v1",
"crashed": false,
}
}
@@ -0,0 +1,7 @@
{
"name": "stress-js-async",
"version": "1.0.0",
"dependencies": {
"pg": "^8.11.0"
}
}
@@ -0,0 +1,37 @@
// 2026-03-19
// stress_js_async.js — делает 3 параллельных запроса к PG через Promise.all.
// Проверяет nodejs20 runtime под умеренной нагрузкой и async/await.
//
// Entrypoint: stress_js_async.run
'use strict';
const { Client } = require('pg');
exports.run = async (event) => {
const client = new Client({
host: process.env.PGHOST,
port: parseInt(process.env.PGPORT || '5432'),
database: process.env.PGDATABASE,
user: process.env.PGUSER,
password: process.env.PGPASSWORD,
ssl: process.env.PGSSLMODE === 'require' ? { rejectUnauthorized: false } : false,
});
await client.connect();
try {
const [ver, cnt, max] = await Promise.all([
client.query('SELECT version() AS v'),
client.query('SELECT COUNT(*) AS cnt FROM terraform_demo_table'),
client.query('SELECT MAX(id) AS max_id FROM terraform_demo_table'),
]);
return {
runtime: 'nodejs20',
version: 'v1',
pg_version: ver.rows[0].v.split(' ').slice(0, 2).join(' '),
total_rows: parseInt(cnt.rows[0].cnt, 10),
max_id: max.rows[0].max_id,
};
} finally {
await client.end();
}
};
@@ -0,0 +1,5 @@
{
"name": "stress-js-badenv",
"version": "1.0.0",
"dependencies": {}
}
@@ -0,0 +1,17 @@
// 2026-03-19
// stress_js_badenv.js — читает несуществующую переменную env и падает.
// Проверяет: платформа перехватывает TypeError/undefined, возвращает 500.
//
// Entrypoint: stress_js_badenv.run
'use strict';
exports.run = async (event) => {
const crash = event.crash !== false; // по умолчанию crash=true
if (crash) {
// Читаем несуществующий env, пытаемся вызвать .toUpperCase() на undefined
const val = process.env.THIS_VAR_DOES_NOT_EXIST_AT_ALL;
return { shout: val.toUpperCase() }; // TypeError: Cannot read properties of undefined
}
return { runtime: 'nodejs20', version: 'v1', crashed: false };
};
@@ -0,0 +1,18 @@
# 2026-03-19
# stress_slow.py — долгая функция: спит N секунд (по умолчанию 8).
# Проверяет что timeout-механизм и параллельные запросы не блокируют друг друга.
import time
import os
_VERSION = "v1"
def run(event):
secs = int(event.get("sleep", 8))
time.sleep(secs)
return {
"version": _VERSION,
"slept_sec": secs,
"pid": os.getpid(),
}
@@ -0,0 +1 @@
psycopg2-binary==2.9.9
@@ -0,0 +1,39 @@
# 2026-03-19
# stress_writer.py — пишет N строк в terraform_demo_table (по умолчанию 5).
# Проверяет параллельные INSERT'ы и устойчивость соединения с PG при нагрузке.
import os
import psycopg2
import time
_VERSION = "v1"
def run(event):
n = int(event.get("rows", 5))
prefix = event.get("prefix", "stress")
conn = psycopg2.connect(
host=os.environ["PGHOST"],
port=int(os.environ.get("PGPORT", "5432")),
dbname=os.environ["PGDATABASE"],
user=os.environ["PGUSER"],
password=os.environ["PGPASSWORD"],
sslmode=os.environ.get("PGSSLMODE", "require"),
)
inserted = []
try:
with conn.cursor() as cur:
for i in range(n):
title = f"{prefix}-{int(time.time()*1000)}-{i}"
cur.execute(
"INSERT INTO terraform_demo_table (title) VALUES (%s) RETURNING id",
(title,),
)
row = cur.fetchone()
inserted.append({"id": row[0], "title": title})
conn.commit()
finally:
conn.close()
return {"version": _VERSION, "inserted": inserted, "count": len(inserted)}