All jobs

Write Unit Tests for a Gin Project

Yes. An agent runs the Gin project's coverage script, finds the functions it leaves uncovered, writes Go testing tests for them and opens a PR with the delta.

Run this on RushIn a Project that has your repository.

What the agent does

The agent measures before it writes. gothinkster/golang-gin-realworld-example-app is three packages, users, articles and common, with Gin 1.10, GORM 2 on SQLite, golang-jwt/jwt/v5 and testify in go.mod under go 1.21. Its readme already reports high coverage, 93.4% for articles, 99.5% for users and 85.7% for common, so the job is not a first suite but the functions the existing one skips. The agent runs bash ./scripts/coverage.sh, which writes an atomic-mode coverage.out across the packages, and then go tool cover -func=coverage.out | sort -k3 -n to list every function by percentage rather than every file, since a 90% package can still hide a function at 0%.

It then reads what the existing tests do so the new ones fit. articles/unit_test.go builds a router with setupRouter(), creates users and articles with createTestUser and createArticleWithUser, and opens the SQLite test database in TestMain through common.TestDBInit(), removing it with common.TestDBFree; users/unit_test.go has newUserModel and userModelMocker, and common/test_helpers.go offers HeaderTokenMock, ExtractTokenFromHeader and VerifyTokenClaims. The uncovered lines are mostly error branches and serializer paths: the tx.Rollback() returns in FindManyArticle and GetArticleFeed in articles/models.go, ResponseWithPreloaded in articles/serializers.go, the fmt.Println fallbacks in common/database.go when a path cannot be created, GenToken's signing-error return in common/utils.go, and the Param() branch of NewValidatorError for tags like min=8.

The agent writes table-driven tests with testing and testify/assert, named for behaviour: TestFindManyArticleRollsBackOnAssociationError, TestResponseWithPreloadedUsesGivenCounts, TestNewValidatorErrorFormatsParam, TestEnsureDirRejectsFilePath. Each exercises the function through its inputs and the SQLite database the package already uses, not by reaching into GORM internals. Where a branch can only be hit by a closed or corrupted database, it opens a second gorm.DB, closes the underlying sql.DB, and calls the function with it, which is enough to reach the error return without a mock framework. Tests that need a user get one from the existing helpers so the shared test database stays consistent.

Before it pushes it runs bash ./scripts/gofmt.sh, bash ./scripts/coverage.sh again on Go 1.21, 1.22 and 1.23 as .github/workflows/ci.yml does, and golangci-lint run with the v1.61 configuration in .golangci.yml (staticcheck, unused, misspell), because a new test file that trips unused fails the Lint job. It does not change production code unless a test reveals a bug; if one does, the fix is a separate commit and the pull request says what it found.

Start it with one API call

POST https://api.prix.dev/o/{org}/sessions with this body:

{
  "agent": "codex",
  "input": "Run bash ./scripts/coverage.sh in this Gin project, then go tool cover -func=coverage.out, and list the functions with the lowest coverage across the users, articles and common packages. Write Go testing tests with testify for the uncovered branches that hold real logic, using the existing helpers (setupRouter, createTestUser, createArticleWithUser, common.TestDBInit and the token helpers in common/test_helpers.go) and the SQLite test database the packages already open in TestMain. Name tests for the behaviour they check, keep them table-driven where several inputs share a shape, and reach error branches through real inputs such as a closed database rather than by mocking GORM. Do not change production code unless a test reveals a bug; if it does, fix it in a separate commit and say so. Run scripts/gofmt.sh, scripts/coverage.sh on Go 1.21, 1.22 and 1.23, and golangci-lint run, then open a pull request with the per-function coverage before and after.",
  "resources": [
    {
      "url": "https://github.com/your-org/your-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

A pull request on its own branch that adds test functions to articles/unit_test.go, users/unit_test.go and common/unit_test.go, or new _test.go files beside them, and leaves the production files unchanged. The description pastes the go tool cover -func lines for the functions it targeted, before and after, with the package totals, and lists the gofmt, coverage.sh and golangci-lint runs on each Go version.

If a test found a bug, such as FindManyArticle committing after a rollback, the description names it, the fix is in its own commit, and the test that found it stays. The session transcript keeps every command with its output, including the coverage listings, and GET /o/{org}/sessions/{id}/messages returns it.

A reviewer checks that the new tests assert behaviour and not SQL strings, that none of them leave rows that break the existing TestArticleFeedCount or TestUserModel, and that the error-branch tests close their own database handle rather than the shared test_db.

Run it on every nightly

Create an automation in the Project with a schedule trigger, a cron such as 0 2 * * * with your timezone, and a prompt asking for tests on the functions whose coverage fell since the last run. Each night opens one pull request on its own branch, and the coverage table in each description is the record of where the suite stands.

Set a webhook URL on the API key and Rush POSTs run.completed when the turn finishes, with the session_url and the result, so a handler can post the pull request link and the package totals into the channel where the team starts its day.

The use case this job follows, with its automation and trigger: Write the missing tests.

Why run it on Rush?

Pushing a well-tested Go project from 90% to the last functions is fiddly work: the gaps are error returns and rollbacks that need a closed database or a bad path to reach, and nobody wants to spend an afternoon on them. The agent finds them from the coverage profile, reaches them with real inputs in its own sandbox, and runs the matrix the workflow runs.

The pull request shows the per-function coverage before and after and the transcript of every run, so the delta is something you can check line by line. Several Go services can each get a run at the same time, and a person still merges each one.

Frequently asked questions

The readme says coverage is already 90%. Is there anything left?

Package totals hide functions at 0%. go tool cover -func lists each function, and the gaps here are error branches: the rollback returns in articles/models.go, the fallback prints in common/database.go, GenToken's signing failure and the Param() branch of NewValidatorError. Those are what the agent targets.

testify or the standard library?

Both, as the project does: testing for structure and testify/assert for assertions, which go.mod already requires. The agent adds no new test framework or mocking library.

Does it need CGO for SQLite?

Yes. gorm.io/driver/sqlite uses mattn/go-sqlite3, which needs a C compiler, and the agent installs one in its sandbox, so the tests run the same way they do in the Test job.

Will it modify the Newman API tests?

No. scripts/run-api-tests.sh and the Postman collection are integration tests of the running server and out of scope for this run. The prompt is about Go unit tests in the three packages.