TT Lab
Get started
Learn Learning paths Courses

Testing Tools in Practice

Test failure paths and side effects in isolation

Continue in TT Lab

Goal

You reproduce call counts, backoff, file preservation, and save failures without a network and without real waiting.

Why it matters

Success on one normal request does not guarantee boundary values or failure recovery. In this lab you implement or test the contract of each function in small pieces and then connect them in real execution. The grader does not look only at whether code exists or at the wording of a report; it checks results, exceptions, and stored state. Keep the code from the earlier steps as you move to the next step.

Steps

  1. In /root/work/test-failures-lab/test_service.py, test that fetch returns the string from send unchanged and calls send exactly once. Pass cache as a pathlib.Path under tmp_path. Do the first preparation with the following command.
mkdir -p /root/work/test-failures-lab
cp /opt/fixtures/practice_depth/test-failures-lab/* /root/work/test-failures-lab/
cd /root/work/test-failures-lab
  1. In /root/work/test-failures-lab/test_service.py, set it up so that the first send raises TimeoutError and the second returns 'fresh', and check that fetch returns 'fresh'.
  2. In /root/work/test-failures-lab/test_service.py, supply a send that keeps raising TimeoutError and check that TimeoutError propagates after a total of 3 calls.
  3. In /root/work/test-failures-lab/test_service.py, test that a send that raises ValueError is called exactly once and that the same kind of exception propagates.
  4. In /root/work/test-failures-lab/test_service.py, check that when every send raises TimeoutError, the values passed to sleep are exactly [0.1, 0.2]. It does not actually sleep.
  5. In /root/work/test-failures-lab/test_service.py, succeed with a Korean string, then read the cache file as UTF-8 and check that the same content was saved.
  6. In /root/work/test-failures-lab/test_service.py, write 'old' to cache beforehand and then make send keep failing. After the exception, check that the file content is still 'old'.
  7. In /root/work/test-failures-lab/test_service.py, test that OSError propagates when writing to cache fails even though send succeeds. If you pass the tmp_path directory itself as cache, the write fails deterministically.

Notes

Catch needless calls on the success path

In /root/work/test-failures-lab/test_service.py, test that fetch returns the string from send unchanged and calls send exactly once. Pass cache as a pathlib.Path under tmp_path. Do the first preparation with the following command.

mkdir -p /root/work/test-failures-lab
cp /opt/fixtures/practice_depth/test-failures-lab/* /root/work/test-failures-lab/
cd /root/work/test-failures-lab

Inject a function that records into a calls list. If you look only at the return value, you miss duplicate calls.

You can reproduce the grading directly with bash /opt/lab/checks/test-failures-lab/01-contract.sh. Save the file and run it again.

Fail once and then recover

In /root/work/test-failures-lab/test_service.py, set it up so that the first send raises TimeoutError and the second returns 'fresh', and check that fetch returns 'fresh'.

Control the order with an iterator or a call count. The test itself must not connect to a real network.

You can reproduce the grading directly with bash /opt/lab/checks/test-failures-lab/02-contract.sh. Save the file and run it again.

Check the total number of attempts and the last exception

In /root/work/test-failures-lab/test_service.py, supply a send that keeps raising TimeoutError and check that TimeoutError propagates after a total of 3 calls.

Three retries and three total attempts are different. In this contract it is 3 calls, including the first request.

You can reproduce the grading directly with bash /opt/lab/checks/test-failures-lab/03-contract.sh. Save the file and run it again.

Prevent retries of a permanent error

In /root/work/test-failures-lab/test_service.py, test that a send that raises ValueError is called exactly once and that the same kind of exception propagates.

You have to check the length of calls as well as the kind of exception to catch the two pointless extra calls.

You can reproduce the grading directly with bash /opt/lab/checks/test-failures-lab/04-contract.sh. Save the file and run it again.

Check the backoff sequence and the last wait

In /root/work/test-failures-lab/test_service.py, check that when every send raises TimeoutError, the values passed to sleep are exactly [0.1, 0.2]. It does not actually sleep.

Pass delays.append as the sleep argument. After the last failure there is no next attempt, so there must be no waiting either.

You can reproduce the grading directly with bash /opt/lab/checks/test-failures-lab/05-contract.sh. Save the file and run it again.

Check the return value and the disk content together

In /root/work/test-failures-lab/test_service.py, succeed with a Korean string, then read the cache file as UTF-8 and check that the same content was saved.

An implementation that returns the success result but forgets to write the file cannot be caught by a return value test alone.

You can reproduce the grading directly with bash /opt/lab/checks/test-failures-lab/06-contract.sh. Save the file and run it again.

Keep a network failure from erasing the existing cache

In /root/work/test-failures-lab/test_service.py, write 'old' to cache beforehand and then make send keep failing. After the exception, check that the file content is still 'old'.

Structure it in the order of setup, then execution with the exception check, then a check of the file state. Do not look only at whether the file exists.

You can reproduce the grading directly with bash /opt/lab/checks/test-failures-lab/07-contract.sh. Save the file and run it again.

Do not turn a save failure into a fake success

In /root/work/test-failures-lab/test_service.py, test that OSError propagates when writing to cache fails even though send succeeds. If you pass the tmp_path directory itself as cache, the write fails deterministically.

Create an error that does not depend on changing permissions. This is a different responsibility from a test that only checks that the success string is returned.

You can reproduce the grading directly with bash /opt/lab/checks/test-failures-lab/08-contract.sh. Save the file and run it again.