# Testes de Load/Stress: Garantindo Performance sob Carga

**Meta Description:** Aprenda testes de carga e stress: JMeter, k6, Gatling. Como simular milhares de usuários e identificar gargalos de performance.

---

## Tipos de Teste de Carga

### Load Testing

Verifica comportamento sob carga esperada.

```
Carga: 1000 usuários simultâneos
Duração: 30 minutos
Métrica: P95 < 500ms
```

### Stress Testing

Vai além dos limites normais.

```
Carga: 1000 → 2000 → 5000 usuários
Objetivo: Encontrar ponto de quebra
```

### Spike Testing

Picos súbitos de carga.

```
Normal: 500 usuários
Spike: 5000 usuários em 5 segundos
Recovery: 500 usuários
```

### Soak Testing

Carga sustentada por longo período.

```
Carga: 1000 usuários
Duração: 8 horas
Objetivo: Memory leaks, degradação
```

---

## k6 - Modern Load Testing

### Instalação

```bash
# macOS
brew install k6

# Linux
sudo apt install k6

# Windows
choco install k6
```

### Script Básico

```javascript
// load-test.js
import http from 'k6/http';
import { check, sleep } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 100 },   // Ramp-up
    { duration: '5m', target: 100 },   // Steady
    { duration: '2m', target: 200 },   // Stress
    { duration: '5m', target: 200 },   // Steady
    { duration: '2m', target: 0 },     // Ramp-down
  ],
  thresholds: {
    http_req_duration: ['p(95)<500'],  // 95% < 500ms
    http_req_failed: ['rate<0.01'],     // < 1% errors
    checks: ['rate>0.95'],              // > 95% checks pass
  },
};

const BASE_URL = 'https://api.exemplo.com';

export default function () {
  // Login
  const loginRes = http.post(`${BASE_URL}/auth/login`, {
    email: 'user@example.com',
    password: 'password123',
  });
  
  check(loginRes, {
    'login status 200': (r) => r.status === 200,
    'has token': (r) => r.json('token') !== undefined,
  });
  
  const token = loginRes.json('token');
  
  // Get products
  const productsRes = http.get(`${BASE_URL}/products`, {
    headers: { 'Authorization': `Bearer ${token}` },
  });
  
  check(productsRes, {
    'products status 200': (r) => r.status === 200,
    'has products': (r) => r.json('items').length > 0,
  });
  
  sleep(1);
}
```

### Cenários Complexos

```javascript
// scenarios.js
import http from 'k6/http';
import { check, group } from 'k6/http';
import { Rate, Trend } from 'k6/metrics';

const errorRate = new Rate('errors');
const apiLatency = new Trend('api_latency');

export const options = {
  scenarios: {
    // Smoke test
    smoke: {
      executor: 'constant-vus',
      vus: 10,
      duration: '1m',
      tags: { test_type: 'smoke' },
    },
    
    // Load test
    load: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '2m', target: 100 },
        { duration: '5m', target: 100 },
        { duration: '2m', target: 0 },
      ],
      tags: { test_type: 'load' },
    },
    
    // Stress test
    stress: {
      executor: 'ramping-arrival-rate',
      startRate: 1,
      timeUnit: '1s',
      preAllocatedVUs: 100,
      maxVUs: 500,
      stages: [
        { duration: '2m', target: 10 },
        { duration: '5m', target: 50 },
        { duration: '2m', target: 100 },
        { duration: '1m', target: 0 },
      ],
      tags: { test_type: 'stress' },
    },
    
    // Spike test
    spike: {
      executor: 'ramping-vus',
      startVUs: 0,
      stages: [
        { duration: '30s', target: 100 },
        { duration: '1m', target: 1000 },  // Spike!
        { duration: '30s', target: 1000 },
        { duration: '2m', target: 0 },
      ],
      tags: { test_type: 'spike' },
    },
  },
};

export default function () {
  const res = http.get('https://api.exemplo.com/health');
  
  errorRate.add(res.status !== 200);
  apiLatency.add(res.timings.duration);
}
```

---

## JMeter - Enterprise Load Testing

### Instalação

```bash
# Download
wget https://jmeter.apache.org/download_jmeter.cgi

# Run
./bin/jmeter.sh
```

### Plano de Teste (GUI)

```
Test Plan
├── Thread Group (100 users, 10s ramp-up, loop 10)
│   ├── HTTP Request Defaults
│   │   └── Server: api.exemplo.com
│   │
│   ├── Once Only Controller
│   │   └── Login Request
│   │       └── POST /auth/login
│   │
│   ├── Recording Controller
│   │   └── GET /products
│   │   └── GET /products/{id}
│   │   └── POST /orders
│   │
│   └── Listeners
│       ├── Summary Report
│       ├── View Results Tree
│       ├── Aggregate Report
│       └── Graph Results
```

### JMeter CLI

```bash
# Run non-GUI
jmeter -n -t test-plan.jmx -l results.jtl -e -o html-report

# With specific properties
jmeter -n -t api-test.jmx \
  -Jthreads=100 \
  -Jrampup=10 \
  -Jduration=300 \
  -l results.jtl
```

### Distributed Testing

```bash
# jmeter-server (on slave machines)
jmeter-server -Djava.rmi.server.hostname=192.168.1.100

# Run distributed
jmeter -n -t test.jmx \
  -R192.168.1.100,192.168.1.101,192.168.1.102 \
  -l results.jtl
```

---

## Gatling - Scala-based Load Testing

### Instalação

```bash
# Download
wget https://repo1.maven.org/maven2/io/gatling/highcharts/gatling-charts-highcharts-bundle/3.10.5/gatling-charts-highcharts-bundle-3.10.5.zip
unzip gatling-charts-highcharts-bundle-3.10.5.zip
```

### Script Scala

```scala
// src/test/scala/LoadSimulation.scala
package simulations

import io.gatling.core.Predef._
import io.gatling.http.Predef._
import io.gatling.jdbc.Predef._
import io.gatling.core.structure.ScenarioBuilder

class ApiLoadSimulation extends Simulation {
  
  val httpProtocol = http
    .baseUrl("https://api.exemplo.com")
    .acceptHeader("application/json")
    .contentTypeHeader("application/json")
    .disableCaching
  
  val userFeeder = csv("users.csv").circular.random
  
  val loginScenario: ScenarioBuilder = scenario("Login Flow")
    .feed(userFeeder)
    .exec(
      http("Login")
        .post("/auth/login")
        .body(StringBody(
          """{"email":"${email}","password":"${password}"}"""
        )).asJson
        .check(jsonPath("$.token").saveAs("authToken"))
    )
    .pause(1)
    .exec(
      http("Get Products")
        .get("/products")
        .header("Authorization", "Bearer ${authToken}")
        .check(status.is(200))
    )
    .pause(1)
    .exec(
      http("Create Order")
        .post("/orders")
        .header("Authorization", "Bearer ${authToken}")
        .body(StringBody(
          """{"productId":1,"quantity":2}"""
        )).asJson
        .check(status.is(201))
    )
  
  setUp(
    loginScenario
      .inject(
        rampUsers(100).during(30.seconds),
        constantUsersPerSec(50).during(5.minutes),
        rampUsers(100).during(30.seconds)
      )
      .protocols(httpProtocol)
  )
  .assertions(
    global.responseTime.percentile(95).lt(500),
    global.successfulRequests.percent.gt(99)
  )
  .thresholds(
    http("Login").responseTime.percentile(99).lt(1000)
  )
}
```

---

## Interpreting Results

### Key Metrics

| Métrica | Significado | Target |
|---------|-------------|--------|
| **P95 Latency** | 95% das requisições | < 500ms |
| **P99 Latency** | 99% das requisições | < 1s |
| **Throughput** | Req/s | > 1000 |
| **Error Rate** | % falhas | < 1% |
| **CPU** | Utilização | < 80% |
| **Memory** | Utilização | < 85% |

### Finding Bottlenecks

```javascript
// k6 com métricas customizadas
import { Trend } from 'k6/metrics';

const dbLatency = new Trend('db_query_duration');
const externalLatency = new Trend('external_api_duration');

export default function () {
  const start = Date.now();
  // DB query
  const dbRes = http.get(`${BASE_URL}/db`);
  dbLatency.add(Date.now() - start);
  
  // External API
  const extStart = Date.now();
  const extRes = http.get('https://external-api.com/data');
  externalLatency.add(Date.now() - extStart);
}
```

---

## Conclusão

Testes de carga são essenciais para garantir performance. As chaves são:

1. **Definir objetivos claros** - SLAs e thresholds
2. **Simular realista** - Dados e comportamento reais
3. **Monitorar infra** - CPU, memória, rede
4. **Analisar resultados** - P95, P99, throughput
5. **Testar regularmente** - CI/CD integrado
