# Integration Testing

Integration tests connect to a real (or Docker) RouterOS device and
verify end-to-end behaviour.  They are organised in `tests/integration/`.

---

## Setup

### 1. Configure `.env`

```bash
cp .env.example .env
```

Edit `.env`:

```env
ROUTEROS_HOST=192.168.1.1    # or 127.0.0.1 for Docker
ROUTEROS_PORT=8728
ROUTEROS_USER=admin
ROUTEROS_PASSWORD=           # blank by default
ROUTEROS_TLS_PORT=8729
ROUTEROS_TLS_VERIFY=false    # for self-signed certs
```

### 2. (Optional) Start Docker

```bash
cd docker && docker compose up -d
# Wait for "(healthy)" in: docker compose ps
```

---

## Running integration tests

```bash
# All integration tests
uv run pytest tests/integration/ -v

# Specific test file
uv run pytest tests/integration/test_commands.py -v

# Specific test class
uv run pytest tests/integration/test_commands.py::TestSystemCommands -v

# Specific test
uv run pytest tests/integration/test_commands.py::TestSystemCommands::test_resource_print -v
```

### Skip when no device

If `ROUTEROS_HOST` is unreachable, the **entire integration suite is
automatically skipped** (no failures).  You will see:

```
SKIPPED [1] tests/integration/conftest.py: RouterOS device not reachable at 127.0.0.1:8728
```

---

## Running all tests (unit + integration)

```bash
uv run pytest -v
```

---

## Running only unit tests

```bash
uv run pytest tests/unit/ -v
```

---

## Coverage

```bash
# Unit tests only
uv run pytest tests/unit/ --cov=routeros --cov-report=term-missing

# All tests
uv run pytest --cov=routeros --cov-report=html
# Open htmlcov/index.html
```

---

## Integration test files

| File | What it tests |
|---|---|
| `test_connection.py` | `dial()`, `dial_tls()`, authentication |
| `test_commands.py` | System/interface/IP commands, error handling |
| `test_async.py` | Concurrent tagged requests |
| `test_listener.py` | Streaming listeners, cancellation |

---

## Writing new integration tests

```python
import pytest

pytestmark = pytest.mark.integration   # mark whole module

class TestMyFeature:
    def test_something(self, client):  # client fixture = authenticated Client
        reply = client.run("/some/command")
        assert reply.done is not None
```

Available fixtures (defined in `tests/integration/conftest.py`):

| Fixture | Description |
|---|---|
| `client` | Authenticated synchronous `Client` |
| `async_client` | Authenticated `Client` with `async_start()` called |
| `ros_address` | `"host:port"` string |
| `ros_tls_address` | TLS `"host:port"` string |
| `ros_credentials` | `(username, password)` tuple |
| `tls_ssl_context` | `ssl.SSLContext` (verify=False for self-signed) |
