seppo 0.1.0

Kubernetes testing framework with multi-cloud cluster management
Documentation
# Seppo: Kubernetes SDK

**Native library. No config files. Just code.**

---

## WHAT IS SEPPO

Seppo connects your code to Kubernetes. That's it.

```rust
// Standalone usage
use seppo::Context;

#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    let ctx = Context::new().await?;

    ctx.apply(&my_deployment).await?;
    ctx.wait_ready("deployment/myapp").await?;

    let pf = ctx.port_forward("svc/myapp", 8080).await?;
    let resp = pf.get("/health").await?;

    ctx.cleanup().await?;
    Ok(())
}
```

```rust
// With test macro
#[seppo::test]
async fn test_my_app(ctx: Context) {
    ctx.apply(&my_deployment).await?;
    ctx.wait_ready("deployment/myapp").await?;

    let resp = ctx.port_forward("svc/myapp", 8080).await?.get("/health").await?;
    assert!(resp.contains("ok"));
}
```

Like `#[tokio::test]` gives you async, `#[seppo::test]` gives you Kubernetes.

---

## CORE PHILOSOPHY

1. **Native library** - Not a CLI, not a framework. A library.
2. **No config files** - No YAML, no TOML. Just Rust code.
3. **Works standalone or with tests** - Use however you want.
4. **kube-rs powered** - Native K8s client, not kubectl shelling.
5. **Failure-friendly** - Keep resources on failure, dump logs, debug easily.

---

## ARCHITECTURE

```
┌─────────────────────────────────────────────────────────────┐
│  Your Code                                                  │
│    └── Context::new()  → standalone usage                   │
│    └── #[seppo::test]  → test macro (optional)              │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│  Your Machine / CI                    Kubernetes Cluster    │
│  ┌─────────────────┐                 ┌─────────────────┐   │
│  │ your app        │ ───kube-rs───► │ Kind / EKS / etc│   │
│  │ (seppo)         │                 │                 │   │
│  └─────────────────┘                 └─────────────────┘   │
└─────────────────────────────────────────────────────────────┘
```

---

## CORE COMPONENTS

### 1. `Context` - K8s Connection

```rust
pub struct Context {
    pub client: kube::Client,
    pub namespace: String,
}

impl Context {
    // Creation
    pub async fn new() -> Result<Self>;  // Creates isolated namespace
    pub async fn cleanup(&self) -> Result<()>;

    // Resource operations
    pub async fn apply<K: Resource>(&self, resource: &K) -> Result<K>;
    pub async fn get<K: Resource>(&self, name: &str) -> Result<K>;
    pub async fn list<K: Resource>(&self) -> Result<Vec<K>>;
    pub async fn delete<K: Resource>(&self, name: &str) -> Result<()>;

    // Waiting
    pub async fn wait_ready(&self, resource: &str) -> Result<()>;
    pub async fn wait_for<K: Resource>(&self, name: &str, condition: F) -> Result<K>;

    // Diagnostics
    pub async fn logs(&self, pod: &str) -> Result<String>;
    pub async fn events(&self) -> Result<Vec<Event>>;

    // Network
    pub async fn port_forward(&self, target: &str, port: u16) -> Result<PortForward, PortForwardError>;
    pub async fn exec(&self, pod: &str, cmd: &[&str]) -> Result<String>;

    // Stack deployment
    pub async fn up(&self, stack: &Stack) -> Result<()>;
}
```

### 2. `#[seppo::test]` - Test Macro (Optional)

```rust
#[seppo::test]
async fn test_my_controller(ctx: Context) {
    // ctx is auto-injected with:
    // - kube::Client
    // - isolated namespace
    // - cleanup on success / diagnostics on failure
}
```

### 3. `Stack` - Environment Builder

```rust
let s = stack()
    .service("frontend")
        .image("fe:test")
        .replicas(4)
        .port(80)
    .service("backend")
        .image("be:test")
        .replicas(2)
        .port(8080)
    .build();

ctx.up(&s).await?;
```

### 4. Fixtures - Resource Builders

```rust
// Builder function style (recommended)
let deploy = deployment("myapp")
    .image("nginx:latest")
    .replicas(3)
    .port(80)
    .env("LOG_LEVEL", "debug")
    .build();

ctx.apply(&deploy).await?;

// Struct style also works
let pod = PodFixture::new("worker")
    .image("busybox")
    .build();
```

### 5. Failure Handling (with test macro)

On test **success**:
- Cleanup namespace
- Delete resources

On test **failure**:
- Keep namespace alive
- Dump pod logs to test output
- Dump events to test output
- Print resource state
- User can debug

```
FAILED: test_my_controller

Namespace: seppo-test-a1b2c3 (kept for debugging)

--- Pod logs (myapp-xyz) ---
Error: connection refused to database:5432

--- Events ---
0:01 Pod scheduled
0:02 Pulling image myapp:test
0:05 BackOff pulling image

--- Resources ---
deployment/myapp  0/1 ready
pod/myapp-xyz     ImagePullBackOff
```

Configurable:
```bash
SEPPO_KEEP_ALL=true          # never cleanup, even on success (debug mode)
```

---

## CURRENT STATE

**Core SDK:**
- `Context` - K8s connection with namespace management
- `#[seppo::test]` - Optional test macro
- `Stack` - Multi-service deployment builder
- `DeploymentFixture`, `PodFixture`, `ServiceFixture` - Resource builders
- `eventually`, `consistently` - Async condition helpers
- Port forwarding and exec
- Diagnostics collection

---

## LANGUAGES

| Language | Crate/Module | K8s Client |
|----------|--------------|------------|
| Rust | `seppo` | kube-rs |
| Go | `ilmari` | client-go |

Same concepts, native implementation.

---

## TDD WORKFLOW

```bash
# RED: Write failing test
cargo test test_context_creates_namespace  # FAILS

# GREEN: Minimal implementation
cargo test test_context_creates_namespace  # PASSES

# REFACTOR: Clean up
cargo test  # ALL PASS

# COMMIT
git commit -m "feat: Context creates isolated namespace"
```

**Small commits. Always green.**

---

## CRATE STRUCTURE

```
seppo/
├── Cargo.toml
├── src/
│   ├── lib.rs
│   ├── context.rs          # Context - main entry point
│   ├── config.rs           # Cluster/Environment config
│   ├── stack.rs            # Stack builder
│   ├── fixtures.rs         # Resource builders
│   ├── assertions.rs       # Semantic assertions
│   ├── eventually.rs       # Async condition helpers
│   ├── diagnostics.rs      # Failure diagnostics
│   ├── portforward.rs      # Port forwarding
│   ├── wait.rs             # Rich wait errors
│   ├── provider/           # Cluster providers
│   ├── telemetry.rs
│   └── metrics.rs
├── seppo-macros/           # Proc macro crate
│   ├── Cargo.toml
│   └── src/lib.rs
└── tests/
    └── macro_test.rs
```

---

## WHAT SEPPO IS NOT

- **Not a CLI** - No `seppo` command
- **Not a test runner** - Works with `cargo test` or standalone
- **Not config-driven** - No YAML/TOML files
- **Not kubectl wrapper** - Uses kube-rs directly

---

## SUCCESS CRITERIA

```rust
// Standalone
let ctx = Context::new().await?;
ctx.apply(&my_deployment).await?;
ctx.wait_ready("deployment/myapp").await?;
ctx.cleanup().await?;

// Or with test macro
#[seppo::test]
async fn test_my_app(ctx: Context) {
    ctx.apply(&my_deployment).await?;
    ctx.wait_ready("deployment/myapp").await?;
}
```

```bash
cargo test  # Just works
```

---

**Connect to K8s. Just code. That's Seppo.**