Practical lab guide
Lab: test an operational analysis toolkit
Run offline algorithm fixtures and explain correctness, cost, and production limits.
On this page
1. Prepare the local exercise
Save the seven preceding bites' Python listings in .local/advanced-design/ inside your MicroBank checkout, using their documented filenames. The listings are independent exercise utilities, not modifications to the application. Use Python 3.11 or later. No dependency installation or network request is required.
cd .local/advanced-design
python3 --version
Create test_toolkit.py in the same directory:
import unittest
from bisect import bisect_left
from random import Random
from complexity import unique_in_order
from events import summarize
from graph_walk import bfs_distances, dfs_reachable
from dependency_order import dependency_order
from topk import top_k_counts
from time_search import lower_bound, interval_indices
from rate_window import SlidingWindow
class ToolkitTests(unittest.TestCase):
def test_ordered_deduplication(self):
self.assertEqual(unique_in_order(["b", "a", "b"]), ["b", "a"])
self.assertEqual(unique_in_order([]), [])
def test_deliveries_and_distinct_events(self):
rows = [{"id": "1", "kind": "timeout"}] * 2
self.assertEqual(summarize(rows), ({"timeout": 2}, {"timeout": 1}, 1))
self.assertEqual(summarize([]), ({}, {}, 0))
with self.assertRaises(ValueError):
summarize([{"id": "", "kind": "timeout"}])
with self.assertRaises(KeyError):
summarize([{"id": "1"}])
def test_cycle_does_not_loop_forever(self):
graph = {"a": ["b", "c"], "b": ["a", "c"], "c": [], "z": []}
self.assertEqual(bfs_distances(graph, "a"), {"a": 0, "b": 1, "c": 1})
self.assertEqual(dfs_reachable(graph, "a"), {"a", "b", "c"})
with self.assertRaises(ValueError):
bfs_distances({"a": ["missing"]}, "a")
def test_precedence_property(self):
graph = {"db": [], "api": ["db", "db"], "check": ["api"], "docs": []}
order = dependency_order(graph)
self.assertEqual(set(order), set(graph))
position = {task: i for i, task in enumerate(order)}
self.assertTrue(all(position[p] < position[t]
for t, parents in graph.items() for p in parents))
self.assertEqual(dependency_order({}), [])
for invalid in ({"a": ["a"]}, {"a": ["b"], "b": ["a"], "c": ["b"]},
{"a": ["missing"]}):
with self.subTest(invalid=invalid), self.assertRaises(ValueError):
dependency_order(invalid)
def test_heap_against_full_sort(self):
rng = Random(41)
for size in range(20):
counts = {f"event-{i}": rng.randrange(6) for i in range(size)}
ranked = sorted(((count, name) for name, count in counts.items()), reverse=True)
for k in (0, 1, 3, size + 2):
expected = [(name, count) for count, name in ranked[:k]]
self.assertEqual(top_k_counts(counts, k), expected)
with self.assertRaises(ValueError):
top_k_counts({"timeout": -1}, 1)
def test_search_against_library_and_linear_filter(self):
rng = Random(42)
for size in range(20):
values = sorted(rng.randrange(10) for _ in range(size))
for target in range(-1, 12):
self.assertEqual(lower_bound(values, target), bisect_left(values, target))
for start, end in ((0, 5), (3, 3), (-1, 11), (7, 9)):
left, right = interval_indices(values, start, end)
self.assertEqual(values[left:right], [v for v in values if start <= v < end])
with self.assertRaises(ValueError):
interval_indices([], 2, 1)
def test_window_boundaries(self):
limiter = SlidingWindow(2, 60)
self.assertEqual([limiter.allow(t) for t in (0, 1, 2, 60, 60, 61)],
[True, True, False, True, False, True])
self.assertLessEqual(len(limiter.accepted), 2)
with self.assertRaises(ValueError):
limiter.allow(59)
with self.assertRaises(ValueError):
limiter.allow(float("nan"))
def test_independent_replicas_have_independent_limits(self):
replicas = [SlidingWindow(2, 60), SlidingWindow(2, 60)]
accepted = sum(replica.allow(0) for replica in replicas for _ in range(2))
self.assertEqual(accepted, 4) # Not a shared global limit of two.
if __name__ == "__main__":
unittest.main()
2. Verify behavior, then change a requirement
python3 -m unittest -v test_toolkit
Expected outcome: eight test methods pass. These fixtures check small local algorithms, not a running MicroBank deployment. Tests against a different implementation, such as full sorting or a linear filter, can expose mistakes that assertions copied from the optimized algorithm miss.
Choose one extension: reject conflicting duplicate-event payloads, return a shortest unweighted path as well as distance, or reverse the documented top-k tie rule. Write a failing example for the new behavior before modifying the function. Retain the existing contract tests unless the requirement intentionally changes.
3. Explain the operating boundary
Write exercise-review.md alongside the files. For each utility, state its invariant, time and space bounds, invalid-input behavior, and one deployment limitation. Explain what happens with a file larger than RAM, many distinct keys, multiple workers, or out-of-order timestamps. Streaming input does not by itself bound maps, sets, or exact quantile structures.
These algorithms analyze data or simulate behavior locally. Do not wire graph reachability to automatic remediation. If later consuming real logs, normalize and redact them first; never copy credentials or customer data into practice fixtures.
Checkpoint
Keep the Python version, actual test result, your added edge case, and the review. Use those results to record what you completed. You can now continue to the optional problem set or the system-design bites; no cluster needs to be started yet.
Read a failure productively
An import error usually means a filename or working directory differs from the setup, before any algorithm was tested. An assertion failure names a behavior to compare with the written contract. In the heap test, the full-sort oracle supplies an independent answer; in the graph test, the precedence property allows several correct orders. Do not replace either with a hardcoded output merely to get green tests.
Before moving on, explain one passing edge case without looking at the implementation. Then save a new failing example for your chosen requirement change. The optional checkpoint offers more patterns; it is not a prerequisite for the design review.
Sources
Python unittest↗. Algorithm references and input contracts are linked in the preceding seven bites. All fixtures and test cases here are newly authored for this path.
Your notes and evidence
Record observations, questions, or links to your work. Keep credentials out of your notes.
Back up or restore this path
Progress and notes stay in this browser. A backup contains only this learning path.