DEV Community

Avery Lin
Avery Lin

Posted on

A Free-Tier Loop That Summarizes Test Failures

A developer once lost an hour each morning to repetitive test failures. The fixes were predictable, yet the time vanished. That hour became a script that runs every morning.

This article builds a small automation loop for free tiers. It uses a free model and a free server. The loop reads test output, explains failures, and posts a verifiable report. This is not a product review or a benchmark. It is a workflow you can copy.

Why this matters

Free tiers usually mean manual work, even with a model. You still glue it to your own workflow. MonkeyCode offers both free model access and a free server option. That combination enables a real, running service for free.

Disclosure: This article was prepared as part of MonkeyCode's product outreach.

The workflow

We build three small pieces: a fetcher, a summarizer, and a verifier. The fetcher reads raw test output from a file. The summarizer calls the free model with that text. The verifier checks the final result for key names.

Step 1: Configure the model

Set two environment variables for the model access. One holds the endpoint, and one holds the key.

export MONKEY_ENDPOINT="https://your-endpoint.example"
export MONKEY_KEY="your-key"
Enter fullscreen mode Exit fullscreen mode

Do not commit these values to version control. Use a local .env file for your development work. On the server, rely on a secret manager.

Step 2: Write the summarizer

The script below is a template for your model. Replace the request body with your model's expected format.

import os
import requests

def summarize_failures(text: str) -> str:
    endpoint = os.environ["MONKEY_ENDPOINT"]
    key = os.environ["MONKEY_KEY"]
    payload = {
        "model": "your-model",
        "messages": [
            {"role": "user", "content": f"Explain these test failures:\n{text}"}
        ]
    }
    resp = requests.post(endpoint, json=payload, headers={"Authorization": f"Bearer {key}"})
    resp.raise_for_status()
    return resp.json()["choices"][0]["message"]["content"]
Enter fullscreen mode Exit fullscreen mode

This is pseudocode, so your model may use a different schema. Always check the current docs before running the script.

Step 3: Verify the output

A model can hallucinate, so we add a simple check. The report must mention every failing test name to pass.

def verify_report(report: str, test_names: list) -> bool:
    return all(name in report for name in test_names)
Enter fullscreen mode Exit fullscreen mode

This is not perfect, but it catches missing references. It does not catch wrong explanations, yet that is enough for a daily digest.

Step 4: Fetch test output

Use a small function to read a test file. In a real setup, this file comes from your CI.

def read_test_output(path: str) -> str:
    with open(path) as f:
        return f.read()
Enter fullscreen mode Exit fullscreen mode

Step 5: Combine everything in a script

Create a single run.py with the functions above. Add a main block that ties them together.

import os
import requests

def read_test_output(path: str) -> str:
    with open(path) as f:
        return f.read()

def summarize_failures(text: str) -> str:
    endpoint = os.environ["MONKEY_ENDPOINT"]
    key = os.environ["MONKEY_KEY"]
    payload = {
        "model": "your-model",
        "messages": [
            {"role": "user", "content": f"Explain these test failures:\n{text}"}
        ]
    }
    resp = requests.post(endpoint, json=payload, headers={"Authorization": f"Bearer {key}"})
    resp.raise_for_status()
    return resp.json()["choices"][0]["message"]["content"]

def verify_report(report: str, test_names: list) -> bool:
    return all(name in report for name in test_names)

if __name__ == "__main__":
    text = read_test_output("tests.log")
    report = summarize_failures(text)
    if verify_report(report, ["test_a", "test_b"]):
        print(report)
    else:
        print("Report missing test names.")
Enter fullscreen mode Exit fullscreen mode

This is a complete script, so save it as run.py. Run it locally first to confirm the flow works.

Now we have a single entry point, which makes deployment easier.

Test the loop with a sample file

Create a sample test log with a known failure. Run the script and check the output.

echo "FAIL test_login" > tests.log
python run.py
Enter fullscreen mode Exit fullscreen mode

The report should mention the failing test name, like test_login. If it does not, your model may need a different prompt. This test gives you confidence before you deploy.

Step 6: Deploy to the free server

MonkeyCode's free server option hosts small scripts like this. Copy your code to the server, then set the same environment variables.

Create a cron job to run the script every morning.

0 7 * * * cd /path/to/app && python run.py >> report.log 2>&1
Enter fullscreen mode Exit fullscreen mode

The server must stay on for the cron job. Free servers often sleep, so check your provider's policy.

Step 7: Verify the deployment

After the first run, inspect the log file. Confirm the report appears and the verification passed.

cat report.log
Enter fullscreen mode Exit fullscreen mode

If the report is empty, test the API manually. If the cron did not run, check the timezone.

Error handling

The script should handle API failures in a graceful way. Wrap the request in a try-except block to catch errors.

try:
    resp = requests.post(...)
    resp.raise_for_status()
except requests.RequestException as e:
    print(f"API call failed: {e}")
    raise
Enter fullscreen mode Exit fullscreen mode

But for a daily cron, you may want to exit with a non-zero code. That way cron can alert you to problems.

import sys
sys.exit(1)
Enter fullscreen mode Exit fullscreen mode

Add this exit call to the exception handler block.

Limitations

Free models have rate limits and can be slow. They may change without notice, so treat this loop as a personal tool.

The free server may have limited storage and no long-running processes. Keep the script short and simple to fit those limits. The free server may also have a cold start, so your cron job may run a few minutes late.

Token allowances shift over time, so check the current docs before relying on them.

Who should not use this

Do not use this for production alerts or security-critical decisions. If you need guaranteed uptime or low latency, pay for a service. If your team depends on immediate alerts, use a paid monitoring service instead.

The point

Limitation forces simplicity, and that is a good thing. A free model and a free server are enough for a useful tool. The loop runs while you sleep, and the report waits in the morning. That extra hour every morning is the real win.

Top comments (0)