/ opencodehub / tests / load / k6-api-lifecycle.js
Swadhin Biswas test(qa): add e2e, integration, unit, and load coverage · 3/6/2026
1c29e63
89 lines · 2.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
/**
 * k6 API Lifecycle Test — authenticated user flows
 * Tests: issue CRUD, repository browse, search
 * Run: k6 run tests/load/k6-api-lifecycle.js --env AUTH_TOKEN=<token>
 */
import { check, group, sleep } from "k6";
import http from "k6/http";
import { Counter, Trend } from "k6/metrics";

const BASE_URL = __ENV.BASE_URL || "http://localhost:4321";
const AUTH_TOKEN = __ENV.AUTH_TOKEN || "";

const apiLatency = new Trend("api_latency", true);
const apiErrors = new Counter("api_errors");

export const options = {
  stages: [
    { duration: "1m", target: 20 },
    { duration: "3m", target: 50 },
    { duration: "2m", target: 50 },
    { duration: "1m", target: 0 },
  ],
  thresholds: {
    api_latency: ["p(95)<500", "p(99)<1000"],
    api_errors: ["count<20"],
    http_req_failed: ["rate<0.05"],
  },
};

function apiGet(path) {
  const headers = AUTH_TOKEN ? { Authorization: `Bearer ${AUTH_TOKEN}` } : {};
  return http.get(`${BASE_URL}${path}`, { headers });
}

function apiPost(path, body) {
  const headers = {
    "Content-Type": "application/json",
    ...(AUTH_TOKEN ? { Authorization: `Bearer ${AUTH_TOKEN}` } : {}),
  };
  return http.post(`${BASE_URL}${path}`, JSON.stringify(body), { headers });
}

export default function () {
  // Scenario 1: Browse repositories
  group("Browse Repos", () => {
    const res = apiGet("/api/repos?page=1&limit=20");
    check(res, { "repos list 2xx": (r) => r.status < 400 });
    apiLatency.add(res.timings.duration);
    if (res.status >= 400) apiErrors.add(1);
    sleep(0.5);
  });

  // Scenario 2: Search
  group("Search", () => {
    const res = apiGet("/api/search?q=test&type=repos");
    check(res, { "search 2xx": (r) => r.status < 400 });
    apiLatency.add(res.timings.duration);
    if (res.status >= 400) apiErrors.add(1);
    sleep(0.5);
  });

  // Scenario 3: Get repo details (use a known test repo or random)
  group("Repo Detail", () => {
    const res = apiGet("/api/repos/admin/test-repo");
    // 404 is acceptable in load testing — we just care about latency
    check(res, { "repo detail ≤ 404": (r) => r.status <= 404 });
    apiLatency.add(res.timings.duration);
    sleep(0.3);
  });

  // Scenario 4: Issues list
  group("Issues List", () => {
    const res = apiGet("/api/repos/admin/test-repo/issues?page=1");
    check(res, { "issues ≤ 404": (r) => r.status <= 404 });
    apiLatency.add(res.timings.duration);
    sleep(0.5);
  });

  // Scenario 5: Metrics endpoint
  group("Metrics", () => {
    const res = apiGet("/api/metrics");
    check(res, { "metrics 2xx": (r) => r.status < 400 });
    apiLatency.add(res.timings.duration);
    sleep(0.3);
  });

  sleep(1);
}