# Write Tests for a Ktor Server

Yes. An agent adds testApplication coverage for registration, login, posting and deleting kweets, runs Gradle test, and opens a pull request.

[Run this on Rush](https://cloud.getrush.ai/run/write-ktor-tests/ktor/), in a Project that has your repository.

## What the agent does

The agent works inside the sample module the prompt names. In ktorio/ktor-samples that is `kweet/`: `build.gradle.kts` applies Kotlin `2.4.20`, the Ktor plugin `3.6.0`, JVM toolchain 17, H2, Exposed, FreeMarker, and test deps `ktor-server-test-host-jvm`, `kotlin-test` and `mockk`. Application code lives under `src/main/kotlin/io/ktor/samples/kweet/` with `Register.kt`, `Login.kt`, `PostNew.kt`, `Delete.kt`, `ViewKweet.kt` and `KweetApplication.kt` wiring `mainWithDependencies(dao)`.

It reads the existing `src/test/kotlin/KweetApplicationTest.kt`. That file already uses `testApplication { application { mainWithDependencies(dao) } }`, mocks `DAOFacade` with mockk, and covers empty home, home with kweets, login failure (302) and login success with cookies. Registration (`post<Register>` in `Register.kt`), posting (`post<PostNew>` in `PostNew.kt` with date/code/text CSRF-style fields) and deletion (`Delete.kt`) have little or no coverage, and error redirects that set `error` query fields are untested.

New tests stay on `testApplication` and the mocked DAO: successful register creating a user and redirecting to the user page; register conflicts when `dao.user` or `dao.userByEmail` already exists; post-new rejecting missing fields and accepting a valid post when the session user matches; delete removing a kweet the user owns and refusing when ownership fails. Assertions check status codes, `Location` headers and substrings in FreeMarker HTML the same way the login tests do.

It runs `./gradlew :kweet:test` from the samples root (or `./gradlew test` inside `kweet/` using the module's `gradlew`), fixes compile or assertion failures, and opens a pull request that only adds test sources unless a tiny test helper in `KweetApplicationTest` must be shared.

## Start it with one API call

`POST https://api.prix.dev/o/{org}/sessions`

```json
{
  "agent": "claude",
  "input": "In the kweet sample, write tests with Ktor's testApplication for registration, login, posting and deleting a kweet, and the error responses. Run ./gradlew test and open a pull request.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-ktor-app"
    }
  ]
}
```

1. **Get an API key.** In the console, open Settings, then API keys, and create a key for your org. Send it in the Authorization header as a Bearer token.
2. **Send the request.** POST the body in request.json to https://api.prix.dev/o/{org}/sessions, with your repository as the resources URL. The run starts in its own cloud sandbox.
3. **Read what came back.** Follow the run on its live stream or wait for the run.completed webhook, then read the result and its trajectory.

## What comes back

What comes back is a pull request that extends `kweet/src/test/kotlin/` (usually `KweetApplicationTest.kt` or a new file beside it) with `testApplication` cases for register, post-new and delete flows. Production route files stay unchanged; the DAO remains mocked so tests do not require a listening port or a real H2 file.

The pull request description lists the Gradle command that passed and which routes each test posts to. The session trajectory keeps Gradle output, mockk verification failures and any retries, so reviewers can see why a redirect assertion was adjusted.

Before merging, a reviewer checks that new tests still call `mainWithDependencies(dao)`, that form bodies use `formUrlEncode` like the login tests, and that error cases assert the redirect targets `Register.kt` and `PostNew.kt` already use. CI should run the same `./gradlew test` path the agent used.

## Run it on every kweet route handler changed

When a pull request touches `kweet/src/main/kotlin/io/ktor/samples/kweet/*.kt`, your server can POST this session body with the repository in `resources` so missing register/post/delete coverage is filled in an isolated sandbox with JDK 17 and Gradle caches.

Configure the API key webhook for `run.completed` / `run.failed` to receive the session URL and post the resulting pull request into the Ktor maintainers' channel. Cap concurrency with the key's `max_concurrent` limit so many sample modules are not tested at once on one key.

## Why run it on Rush?

Ktor's `testApplication` is fast, but wiring FreeMarker, sessions and mockk still means a full Gradle JVM test run. Rush runs that in a sandbox with the module's toolchain, so you are not stuck waiting on `./gradlew test` locally or polluting your machine with H2 files from accidental non-mocked runs. FreeMarker templates under `src/main/resources/templates/` stay fixtures for HTML assertions rather than being rewritten for tests.

You get a pull request whose proof is green Gradle output in the trajectory, not a claim that routes were tested. Parallel runs can cover other samples (jwt-auth-tests, postgres) with the same request shape while this one finishes kweet.

## Frequently asked questions

### Does it start a real Netty server on a port?

No. It uses `io.ktor.server.testing.testApplication` and `ktor-server-test-host`, the same engine as the existing kweet tests. No public port is bound.

### Why mock the DAO instead of using H2?

The sample's tests already inject a mockk `DAOFacade` through `mainWithDependencies`. Staying on that pattern keeps tests focused on HTTP behaviour and matches `KweetApplicationTest.kt` today. If you ask for Exposed integration tests, say so in the prompt.

### Which Gradle command runs?

Inside the kweet module, `./gradlew test`, or from the repo root the project path that builds kweet. The agent uses the wrapper committed next to the sample so the Kotlin and Ktor plugin versions stay pinned.

### Will it duplicate the existing login tests?

It keeps `testLoginFail` and `testLoginSuccess` and adds the missing register, post and delete paths. If login coverage is already enough, it only references those tests in the pull request description.
