k6 Performance Testing Guide

← Docs v0.50+
1

Introduction

Overview

k6 is a modern, developer-friendly load testing tool built for testing the performance and reliability of APIs, microservices, and websites. Written in Go, it uses JavaScript (ES6+) for test scripts.

Why k6?

✅ Developer-Friendly

  • Write tests in JavaScript/ES6+
  • Familiar syntax for developers
  • Easy to learn and use
  • Great documentation

⚡ High Performance

  • Written in Go for efficiency
  • Low resource consumption
  • Handles thousands of VUs
  • Fast execution

🔧 CLI-First

  • Easy CI/CD integration
  • Scriptable and automatable
  • No GUI required
  • Version control friendly

☁️ Cloud-Ready

  • Grafana Cloud integration
  • Multi-region testing
  • Advanced analytics
  • Team collaboration

Key Features

  • Protocol Support: HTTP/1.1, HTTP/2, WebSockets, gRPC
  • Browser Testing: Real browser automation with Chromium
  • Custom Metrics: Track business-specific KPIs
  • Thresholds: Define pass/fail criteria
  • Scenarios: Complex test orchestration
  • Extensions: Extend functionality with Go
2

Installation

Setup

Windows Installation

powershell
# Option 1: Using Chocolatey
choco install k6

# Option 2: Using Winget
winget install k6 --source winget

# Option 3: Using Scoop
scoop install k6

macOS Installation

bash
# Using Homebrew
brew install k6

Linux Installation

bash
# Debian/Ubuntu
sudo gpg -k
sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg \
  --keyserver hkp://keyserver.ubuntu.com:80 \
  --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | \
  sudo tee /etc/apt/sources.list.d/k6.list
sudo apt-get update
sudo apt-get install k6

# Fedora/CentOS
sudo dnf install https://dl.k6.io/rpm/repo.rpm
sudo dnf install k6

Verify Installation

bash
k6 version
💡 Expected Output: k6 v0.50.0 (go1.21.5, windows/amd64)
3

Core Concepts

Fundamentals

Virtual Users (VUs)

Virtual Users simulate concurrent users interacting with your system. Each VU runs your test script independently in a loop.

javascript
export const options = {
  vus: 10,        // 10 concurrent users
  duration: '30s' // for 30 seconds
};

Stages

Stages allow you to ramp load up and down, simulating realistic traffic patterns.

javascript
export const options = {
  stages: [
    { duration: '30s', target: 10 },  // Ramp up to 10 VUs
    { duration: '1m', target: 10 },   // Stay at 10 VUs
    { duration: '30s', target: 0 }    // Ramp down to 0
  ]
};

Thresholds

Thresholds define pass/fail criteria for your tests. If any threshold fails, k6 exits with a non-zero status code.

javascript
export const options = {
  thresholds: {
    http_req_duration: ['p(95)<500'],    // 95% of requests < 500ms
    http_req_failed: ['rate<0.1'],       // Less than 10% failures
    checks: ['rate>0.9']                 // More than 90% checks pass
  }
};

Checks

Checks are like assertions - they validate responses but don't stop execution on failure.

javascript
import { check } from 'k6';

check(response, {
  'status is 200': (r) => r.status === 200,
  'response time < 500ms': (r) => r.timings.duration < 500,
  'body contains text': (r) => r.body.includes('success')
});
📝 Checks vs Thresholds:
  • Checks: Validate individual responses, don't fail the test
  • Thresholds: Aggregate metrics, fail the test if not met
4

Metrics Deep Dive

Metrics

Built-in HTTP Metrics

k6 automatically collects these metrics for every HTTP request:

Metric Description Type
http_req_durationTotal request timeTrend
http_req_blockedTime waiting for TCP connectionTrend
http_req_connectingTime establishing TCP connectionTrend
http_req_tls_handshakingTime for TLS handshakeTrend
http_req_sendingTime sending requestTrend
http_req_waitingTime waiting for response (TTFB)Trend
http_req_receivingTime receiving responseTrend
http_req_failedRate of failed requestsRate
http_reqsTotal number of requestsCounter

HTTP Timing Breakdown

text
|--blocked--|--connecting--|--tls_handshaking--|--sending--|--waiting--|--receiving--|
                                                                  ↑
                                                    Server processing time (TTFB)

Custom Metrics

k6 provides 4 custom metric types for tracking business-specific KPIs:

1. Counter - Cumulative Sum

Tracks a running total (only increases).

javascript
import { Counter } from 'k6/metrics';
const errorCount = new Counter('custom_errors');

export default function() {
  errorCount.add(1);  // Increment by 1
}

Use for: Total errors, successful operations, items processed

2. Gauge - Latest Value

Tracks the most recent value (like a speedometer).

javascript
import { Gauge } from 'k6/metrics';
const activeConnections = new Gauge('active_connections');

export default function() {
  activeConnections.add(5);  // Now shows 5
}

Use for: Current active users, memory usage, queue size

3. Trend - Statistical Analysis

Tracks multiple values and calculates statistics (min, max, avg, percentiles).

javascript
import { Trend } from 'k6/metrics';
const responseTime = new Trend('custom_response_time');

export default function() {
  const res = http.get('https://api.example.com');
  responseTime.add(res.timings.waiting);  // Track server processing time
}

Use for: Response times, processing durations, file sizes

4. Rate - Success/Failure Ratio

Tracks percentage of true vs false values.

javascript
import { Rate } from 'k6/metrics';
const successRate = new Rate('success_rate');

export default function() {
  const res = http.get('https://api.example.com');
  successRate.add(res.status === 200);  // true or false
}

Use for: Success rates, error rates, pass/fail ratios

5

Test Types

Test Types

Different test types serve different purposes. Choose the right test type for your goals.

1. Smoke Test 🔥

Purpose: Verify system works under minimal load

Configuration

  • VUs: 1-2
  • Duration: 30s - 1m
  • Goal: Catch basic errors

When to Use

  • Before every deployment
  • As a sanity check
  • Before larger tests
javascript
export const options = {
  vus: 1,
  duration: '30s',
  thresholds: {
    http_req_duration: ['p(95)<500'],
    http_req_failed: ['rate<0.01']
  }
};

2. Load Test 📈

Purpose: Test system under expected normal traffic

Configuration

  • VUs: 10-100
  • Duration: 5-15 minutes
  • Goal: Validate typical performance

When to Use

  • Regular performance validation
  • Baseline establishment
  • SLA verification
javascript
export const options = {
  stages: [
    { duration: '2m', target: 10 },   // Ramp up
    { duration: '5m', target: 10 },   // Stay at load
    { duration: '2m', target: 0 }     // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<400'],
    http_req_failed: ['rate<0.05']
  }
};

3. Stress Test 💪

Purpose: Find the breaking point of your system

Configuration

  • VUs: 100-500+
  • Duration: 10-20 minutes
  • Goal: Find maximum capacity

When to Use

  • Capacity planning
  • Finding bottlenecks
  • Failure mode testing
javascript
export const options = {
  stages: [
    { duration: '2m', target: 10 },
    { duration: '5m', target: 50 },
    { duration: '2m', target: 100 },
    { duration: '5m', target: 100 },
    { duration: '2m', target: 0 }
  ]
};

4. Spike Test ⚡

Purpose: Test system resilience to sudden traffic surges

Configuration

  • VUs: Sudden jump (5 → 100)
  • Duration: 5-10 minutes
  • Goal: Validate auto-scaling

When to Use

  • Testing auto-scaling
  • Flash sale scenarios
  • Sudden traffic spikes
javascript
export const options = {
  stages: [
    { duration: '10s', target: 5 },
    { duration: '1m', target: 100 },   // Sudden spike!
    { duration: '10s', target: 5 },
    { duration: '3m', target: 5 },
    { duration: '10s', target: 0 }
  ]
};

5. Soak Test ⏱️

Purpose: Find memory leaks and degradation over time

Configuration

  • VUs: Moderate (20-50)
  • Duration: 1-24 hours
  • Goal: Identify resource leaks

When to Use

  • Before major releases
  • Stability validation
  • Memory leak detection
javascript
export const options = {
  stages: [
    { duration: '2m', target: 20 },
    { duration: '3h', target: 20 },    // Extended duration
    { duration: '2m', target: 0 }
  ]
};
6

Writing Your First Test

Tutorial

Basic HTTP GET Test

javascript
import { sleep } from 'k6';
import http from 'k6/http';

export const options = {
  vus: 3,
  duration: '10s',
  thresholds: {
    http_req_duration: ['p(95)<500'],
    http_req_failed: ['rate<0.1']
  }
};

export default function() {
  http.get('https://test.k6.io');
  sleep(1);  // Think time between requests
}

Run the Test

bash
k6 run test.js

Understanding the Output

text
scenarios: (100.00%) 1 scenario, 3 max VUs, 40s max duration
default: 3 looping VUs for 10s

✓ http_req_duration..............: avg=225ms min=216ms med=229ms max=231ms p(95)=231ms
✓ http_req_failed................: 0.00%  ✓ 0   ✗ 24
  http_reqs......................: 24     2.31/s
  iteration_duration.............: avg=1.29s min=1.21s med=1.22s max=1.76s
  iterations.....................: 24     2.31/s
  vus............................: 3      min=3  max=3
💡 Key Metrics:
  • = Threshold passed
  • = Threshold failed
  • p(95) = 95th percentile (95% of requests were faster)
  • http_reqs = Total requests made
  • iterations = How many times the default function ran

POST Request with JSON

javascript
import http from 'k6/http';
import { check } from 'k6';

export default function() {
  const url = 'https://httpbin.test.k6.io/post';
  const payload = JSON.stringify({
    username: 'testuser',
    password: 'password123'
  });
  
  const params = {
    headers: {
      'Content-Type': 'application/json'
    }
  };
  
  const res = http.post(url, payload, params);
  
  check(res, {
    'status is 200': (r) => r.status === 200,
    'response has json': (r) => r.json('json') !== undefined
  });
}
7

Advanced Features

Advanced

Groups

Organize related requests and get separate metrics for each group.

javascript
import { group } from 'k6';
import http from 'k6/http';

export default function() {
  group('User Login', () => {
    http.post('https://api.example.com/login', payload);
  });
  
  group('Browse Products', () => {
    http.get('https://api.example.com/products');
  });
  
  group('Add to Cart', () => {
    http.post('https://api.example.com/cart', item);
  });
}

Tags

Label requests for filtering and analysis.

javascript
http.get('https://api.example.com/users', {
  tags: { name: 'api', endpoint: 'users' }
});

// Set thresholds for tagged requests
export const options = {
  thresholds: {
    'http_req_duration{name:api}': ['p(95)<500']
  }
};

Data Parameterization

Load test data from external files.

javascript
import { SharedArray } from 'k6/data';
import papaparse from 'https://jslib.k6.io/papaparse/5.1.1/index.js';

const csvData = new SharedArray('users', function() {
  return papaparse.parse(open('./users.csv'), { header: true }).data;
});

export default function() {
  const user = csvData[Math.floor(Math.random() * csvData.length)];
  
  const payload = JSON.stringify({
    username: user.username,
    password: user.password
  });
  
  http.post('https://api.example.com/login', payload);
}

Scenarios

Run multiple test scenarios simultaneously with different configurations.

javascript
export const options = {
  scenarios: {
    smoke_test: {
      executor: 'constant-vus',
      exec: 'smokeTest',
      vus: 1,
      duration: '30s'
    },
    load_test: {
      executor: 'ramping-vus',
      exec: 'loadTest',
      startVUs: 0,
      stages: [
        { duration: '2m', target: 10 },
        { duration: '5m', target: 10 },
        { duration: '2m', target: 0 }
      ],
      startTime: '30s'  // Start after smoke test
    }
  }
};

export function smokeTest() {
  http.get('https://api.example.com/health');
}

export function loadTest() {
  http.get('https://api.example.com/products');
}

Executors

Control how VUs and iterations are scheduled.

Executor Description Use Case
shared-iterationsFixed total iterations shared among VUsExact number of test runs
per-vu-iterationsEach VU runs fixed iterationsGuaranteed iterations per VU
constant-vusFixed number of VUs for durationSteady load
ramping-vusGradually increase/decrease VUsLoad/stress tests
constant-arrival-rateFixed request rateThroughput testing
ramping-arrival-rateGradually change request rateGradual load increase

Dynamic Data Handling

Extract and reuse dynamic values like tokens and IDs.

javascript
export default function() {
  // Login and get token
  const loginRes = http.post('https://api.example.com/login', payload);
  const token = loginRes.json('token');
  
  // Use token in subsequent requests
  const params = {
    headers: {
      'Authorization': `Bearer ${token}`
    }
  };
  
  const profileRes = http.get('https://api.example.com/profile', params);
  
  check(profileRes, {
    'authenticated': (r) => r.status === 200
  });
}

Environment Variables

Keep sensitive data out of scripts.

javascript
const BASE_URL = __ENV.BASE_URL || 'https://api.example.com';
const API_KEY = __ENV.API_KEY;

export default function() {
  http.get(`${BASE_URL}/data`, {
    headers: { 'X-API-Key': API_KEY }
  });
}
bash
# Run with environment variables
k6 run -e BASE_URL=https://staging.api.com -e API_KEY=secret test.js
8

Browser Testing

Browser

k6 supports browser automation for testing real user interactions using Chromium.

Basic Browser Test

javascript
import { browser } from 'k6/browser';
import { check } from 'k6';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      options: {
        browser: {
          type: 'chromium',
          headless: true  // Set to false for debugging
        }
      }
    }
  }
};

export default async function() {
  const page = await browser.newPage();
  
  try {
    await page.goto('https://example.com/login');
    
    await page.locator('#username').fill('testuser');
    await page.locator('#password').fill('password123');
    await page.locator('button[type="submit"]').click();
    
    await page.waitForSelector('.success-message');
    
    const successText = await page.locator('.success-message').textContent();
    
    check(successText, {
      'login successful': (text) => text.includes('Welcome')
    });
  } finally {
    await page.close();
  }
}

Browser Selectors

javascript
// CSS Selector
await page.locator('.login-button').click();

// XPath
await page.locator("//button[text()='Login']").click();

// Playwright-style
await page.getByRole('button', { name: 'Login' }).click();
await page.getByPlaceholder('Username').fill('user');
await page.getByText('Welcome').isVisible();

Combining Browser + API Tests

Test both frontend and backend simultaneously.

javascript
import { browser } from 'k6/browser';
import http from 'k6/http';

export const options = {
  scenarios: {
    ui: {
      executor: 'shared-iterations',
      exec: 'browserTest',
      vus: 2,
      iterations: 4
    },
    api: {
      executor: 'constant-vus',
      exec: 'apiTest',
      vus: 10,
      duration: '1m'
    }
  }
};

export async function browserTest() {
  const page = await browser.newPage();
  await page.goto('https://example.com');
  await page.close();
}

export function apiTest() {
  http.get('https://api.example.com/products');
}
💡 Browser Testing Tips:
  • Use headless: true for CI/CD environments
  • Browser tests consume more resources than API tests
  • Limit concurrent browser VUs (2-5 typically)
  • Always close pages to free resources
9

Cloud Integration

Cloud

Grafana Cloud k6 allows you to run tests from multiple geographic locations and get detailed analytics.

Setup

  1. Create account at app.k6.io
  2. Get your API token from the dashboard
  3. Login via CLI: k6 cloud login
  4. Enter your stack name and paste your token

Cloud Configuration

javascript
export const options = {
  cloud: {
    projectID: 1234567,
    name: 'My Performance Test',
    distribution: {
      'amazon:us:ashburn': { loadZone: 'amazon:us:ashburn', percent: 50 },
      'amazon:eu:dublin': { loadZone: 'amazon:eu:dublin', percent: 50 }
    }
  },
  stages: [
    { duration: '5m', target: 100 }
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'],
    http_req_failed: ['rate<0.01']
  }
};

Running Cloud Tests

bash
# Run test in cloud
k6 cloud test.js

# Run locally and stream results to cloud
k6 run --out cloud test.js

Available Load Zones

Region Load Zone
US East (Virginia)amazon:us:ashburn
US West (Oregon)amazon:us:portland
Europe (Ireland)amazon:ie:dublin
Europe (Frankfurt)amazon:de:frankfurt
Asia Pacific (Tokyo)amazon:jp:tokyo
Asia Pacific (Singapore)amazon:sg:singapore
Asia Pacific (Sydney)amazon:au:sydney
South America (São Paulo)amazon:br:sao-paulo

Cloud Benefits

🌍 Multi-Region Testing

  • Test from 15+ locations worldwide
  • Simulate global user base
  • Identify regional issues

📊 Advanced Analytics

  • Detailed performance insights
  • Visual dashboards
  • Historical comparisons

👥 Team Collaboration

  • Share results with team
  • Centralized test management
  • Role-based access control

🔄 CI/CD Integration

  • Automated performance testing
  • Trend analysis over time
  • Performance regression detection
10

Best Practices

Best Practices

1. Start Small

Always run a smoke test before larger tests to catch basic errors.

bash
k6 run --vus 1 --duration 30s test.js

2. Use Realistic Think Time

Add sleep() to simulate real user behavior.

javascript
import { sleep } from 'k6';

export default function() {
  http.get('https://api.example.com/products');
  sleep(Math.random() * 3 + 1);  // 1-4 seconds
  
  http.get('https://api.example.com/cart');
  sleep(2);
}

3. Set Meaningful Thresholds

Base thresholds on business requirements and SLAs.

javascript
thresholds: {
  http_req_duration: ['p(95)<500'],              // 95% under 500ms
  http_req_failed: ['rate<0.01'],                // Less than 1% errors
  'http_req_duration{name:api}': ['p(99)<1000']  // Critical API
}

4. Use Groups for Organization

javascript
group('User Journey', () => {
  group('Login', () => { /* ... */ });
  group('Browse', () => { /* ... */ });
  group('Checkout', () => { /* ... */ });
});

5. Monitor Custom Metrics

Track business-specific metrics.

javascript
import { Counter, Rate } from 'k6/metrics';

const successfulOrders = new Counter('successful_orders');
const authRate = new Rate('authentication_rate');

export const options = {
  thresholds: {
    successful_orders: ['count>100'],
    authentication_rate: ['rate>0.95']
  }
};

6. Validate Responses

Always check responses, not just status codes.

javascript
check(response, {
  'status is 200': (r) => r.status === 200,
  'response has data': (r) => r.json('data') !== undefined,
  'data is not empty': (r) => r.json('data').length > 0,
  'response time OK': (r) => r.timings.duration < 500
});

7. Ramp Load Gradually

Avoid shocking your system with sudden load.

javascript
stages: [
  { duration: '2m', target: 10 },   // Gradual ramp
  { duration: '5m', target: 10 },   // Sustained load
  { duration: '2m', target: 0 }     // Cool down
]

8. Test in Non-Production First

Always test in staging/QA environments before production testing.

✅ DO

  • Start with smoke tests
  • Use realistic think times
  • Set meaningful thresholds
  • Validate response content
  • Ramp load gradually
  • Monitor system resources
  • Test in staging first
  • Use environment variables

❌ DON'T

  • Skip smoke tests
  • Use zero think time
  • Ignore response validation
  • Spike load immediately
  • Test only status codes
  • Hardcode credentials
  • Test production directly
  • Ignore error messages
11

CI/CD Integration

CI/CD

Integrate k6 performance tests into your CI/CD pipeline for automated performance validation.

GitHub Actions

yaml
name: k6 Performance Tests

on:
  push:
    branches: [main, develop]
  pull_request:
  schedule:
    - cron: '0 2 * * *'  # Daily at 2 AM

jobs:
  performance-test:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Run k6 smoke test
        uses: grafana/k6-action@v0.3.1
        with:
          filename: tests/smoke.js
      
      - name: Run k6 load test
        uses: grafana/k6-action@v0.3.1
        with:
          filename: tests/load.js
        env:
          K6_CLOUD_TOKEN: ${{ secrets.K6_CLOUD_TOKEN }}
      
      - name: Upload results
        if: always()
        uses: actions/upload-artifact@v4
        with:
          name: k6-results
          path: |
            summary.json
            results.json
          retention-days: 7

GitLab CI

yaml
stages:
  - test

k6-performance:
  stage: test
  image: grafana/k6:latest
  script:
    - k6 run --out json=results.json tests/load.js
  artifacts:
    paths:
      - results.json
    expire_in: 1 week
  only:
    - main
    - develop

Azure Pipelines

yaml
trigger:
  - main
  - develop

pool:
  vmImage: 'ubuntu-latest'

steps:
  - script: |
      sudo gpg -k
      sudo gpg --no-default-keyring --keyring /usr/share/keyrings/k6-archive-keyring.gpg \
        --keyserver hkp://keyserver.ubuntu.com:80 \
        --recv-keys C5AD17C747E3415A3642D57D77C6C491D6AC1D69
      echo "deb [signed-by=/usr/share/keyrings/k6-archive-keyring.gpg] https://dl.k6.io/deb stable main" | \
        sudo tee /etc/apt/sources.list.d/k6.list
      sudo apt-get update
      sudo apt-get install k6
    displayName: 'Install k6'
  
  - script: k6 run tests/load.js
    displayName: 'Run k6 tests'
  
  - task: PublishTestResults@2
    inputs:
      testResultsFormat: 'JUnit'
      testResultsFiles: '**/results.xml'

Docker Integration

bash
# Run k6 in Docker
docker run --rm -v $(pwd):/tests grafana/k6:latest run /tests/load.js

# With environment variables
docker run --rm \
  -e K6_CLOUD_TOKEN=$K6_CLOUD_TOKEN \
  -v $(pwd):/tests \
  grafana/k6:latest cloud /tests/load.js

Fail Pipeline on Threshold Violations

javascript
export const options = {
  thresholds: {
    http_req_duration: ['p(95)<500'],
    http_req_failed: ['rate<0.01']
  }
};

// k6 exits with code 99 if thresholds fail
// CI/CD pipeline will fail automatically

Export Results for Analysis

bash
# Export to JSON
k6 run --out json=results.json test.js

# Export to CSV
k6 run --out csv=results.csv test.js

# Export to InfluxDB
k6 run --out influxdb=http://localhost:8086/k6 test.js

# Multiple outputs
k6 run --out json=results.json --out influxdb=http://localhost:8086/k6 test.js

Performance Trend Tracking

yaml
# GitHub Actions - Track performance over time
- name: Run k6 and export results
  run: |
    k6 run --out json=results.json tests/load.js
    
- name: Parse results
  run: |
    P95=$(jq '.metrics.http_req_duration.values["p(95)"]' results.json)
    echo "P95_LATENCY=$P95" >> $GITHUB_ENV
    
- name: Comment on PR
  uses: actions/github-script@v7
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: `## Performance Test Results\n\n- P95 Latency: ${process.env.P95_LATENCY}ms`
      })
12

Quick Reference

Reference

Common Commands

Command Description
k6 run test.jsRun a test
k6 run --vus 10 --duration 30s test.jsRun with custom VUs and duration
k6 run -e BASE_URL=https://api.com test.jsRun with environment variables
k6 cloud test.jsRun in Grafana Cloud
k6 run --out json=results.json test.jsExport results to JSON
k6 run --verbose test.jsRun with verbose output
k6 inspect test.jsValidate test script
k6 versionShow k6 version

Percentile Guide

Percentile Meaning
p(50)Median - 50% of requests were faster
p(90)90% of requests were faster
p(95)95% of requests were faster (common SLA)
p(99)99% of requests were faster
p(99.9)99.9% of requests were faster (tail latency)

Threshold Operators

javascript
thresholds: {
  http_req_duration: ['p(95)<500'],              // Less than
  http_req_failed: ['rate<0.01'],                // Less than 1%
  checks: ['rate>0.95'],                         // Greater than 95%
  http_reqs: ['count>1000'],                     // More than 1000 requests
  'http_req_duration{name:api}': ['avg<200']     // Average less than 200ms
}

Test Script Template

javascript
import { check, group, sleep } from 'k6';
import http from 'k6/http';
import { Rate, Counter, Trend } from 'k6/metrics';

// Custom metrics
const errorRate = new Rate('errors');
const successfulRequests = new Counter('successful_requests');
const customDuration = new Trend('custom_duration');

// Test configuration
export const options = {
  stages: [
    { duration: '1m', target: 10 },
    { duration: '3m', target: 10 },
    { duration: '1m', target: 0 }
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'],
    http_req_failed: ['rate<0.01'],
    errors: ['rate<0.1']
  }
};

// Setup function (runs once)
export function setup() {
  // Prepare test data
  return { token: 'test-token' };
}

// Main test function
export default function(data) {
  group('API Tests', () => {
    const res = http.get('https://api.example.com/data');
    
    const success = check(res, {
      'status is 200': (r) => r.status === 200,
      'response time OK': (r) => r.timings.duration < 500
    });
    
    if (success) {
      successfulRequests.add(1);
    } else {
      errorRate.add(1);
    }
    
    customDuration.add(res.timings.duration);
  });
  
  sleep(1);
}

// Teardown function (runs once)
export function teardown(data) {
  // Cleanup
}

Useful Resources