LESSON 4 OF 4
Independent tests, an export adapter and an operational review
Test both the result and the request history
Save this as test_asset_client.py beside the collector:
import unittest
from asset_client import ApiError, BASE, FixtureTransport, Response, baseline_transport, collect, json_response
class ClientTests(unittest.TestCase):
def test_baseline_two_pages(self):
transport = baseline_transport()
actual = collect(transport, lambda seconds: None)
self.assertEqual(actual, [
{'id':'A-001','owner_id':'u101','site':'HQ'},
{'id':'A-002','owner_id':'u102','site':'HQ'},
{'id':'A-003','owner_id':'u103','site':'BRANCH'},
])
self.assertEqual(len(transport.calls), 2)
def test_rate_limit_wait_then_success(self):
ok = json_response({'items':[], 'next':None, 'total':0})
transport = FixtureTransport({BASE:[Response(429,{'retry-after':'2'},b''),ok]})
delays = []
self.assertEqual(collect(transport, delays.append), [])
self.assertEqual(delays, [2])
self.assertEqual(len(transport.calls), 2)
def test_forbidden_not_retried(self):
transport = FixtureTransport({BASE:[Response(403,{},b'')]})
with self.assertRaisesRegex(ApiError,'Non-retryable'):
collect(transport, lambda seconds: None)
self.assertEqual(len(transport.calls), 1)
def test_cross_origin_next_not_requested(self):
transport = FixtureTransport({BASE:[json_response({'items':[], 'next':'https://other.example/v1/assets?cursor=x', 'total':0})]})
with self.assertRaisesRegex(ApiError,'approved origin'):
collect(transport, lambda seconds: None)
self.assertEqual(len(transport.calls), 1)
def test_terminal_count_must_reconcile(self):
transport = FixtureTransport({BASE:[json_response({'items':[], 'next':None, 'total':3})]})
with self.assertRaisesRegex(ApiError,'does not reconcile'):
collect(transport, lambda seconds: None)
def test_timeouts_have_a_finite_budget(self):
transport = FixtureTransport({BASE:[TimeoutError(),TimeoutError(),TimeoutError()]})
delays = []
with self.assertRaisesRegex(ApiError,'retry budget'):
collect(transport, delays.append)
self.assertEqual(len(transport.calls),3)
self.assertEqual(delays,[1,2])
if __name__ == '__main__':
unittest.main()
Run python -m unittest -v. The baseline result is a literal expected list. Retry tests inspect delays and request counts. The foreign-next-link test verifies that only the initial request happened. The timeout test verifies a finite attempt budget instead of merely waiting for an eventual exception.
Introduce a deliberate defect in a separate copy: return immediately after validating page one. The baseline test must fail because A-003 is missing and only one page was requested. Restore the program and rerun. This demonstrates that the tests distinguish a complete collector from a plausible first-page demo.
Add your own test for a cursor cycle and for a duplicate item on page two. Choose data that would produce different results if the faulty implementation silently overwrote a prior item. A fixture with no duplicate cannot verify a duplicate-rejection rule.
Project A — Export into the inventory reconciliation contract
Build a wrapper that calls the collector, maps id to asset_id, and writes the accepted fields to observed.csv plus an export manifest. Use a newly reserved output directory and never overwrite inputs. The manifest should record complete only after collection and export succeed.
Use the returned item count for the exported row count, and a timezone-aware capture timestamp whose meaning you document. In a real paginated collection, the start and finish timestamps may both be useful. A single timestamp must not falsely imply that every record was observed at exactly that instant.
If collection fails on page two, the wrapper must not publish a successful empty or partial observed inventory. Demonstrate this with the timeout fixture. Then use a valid two-page export with the Python automation course's register input and explain its comparison results.
Worked mapping and reconciliation expectations
The valid API fixture exports A-001/u101/HQ, A-002/u102/HQ and A-003/u103/BRANCH. Compared with that course’s four-row register, the only finding is A-004 as register-only. The API has supplied three assets, so the observed export manifest must declare three parsed records, not four and not two.
Project B — Add a total deadline with a controllable clock
Design a total collection deadline in addition to per-request timeout and page limits. Inject a clock into the collector so tests can advance time without real sleeping. Decide whether a retry may start when the remaining deadline is shorter than the planned delay plus a request timeout. State your choice explicitly.
Use cases with time remaining, a deadline reached exactly at a boundary, and a delay longer than the remaining budget. Ensure the collector raises a clear failure and does not return partial items as complete. If you add real sleeping later, use a monotonic clock for elapsed-time reasoning rather than assuming the wall clock never changes.
A total deadline is not the same as a scheduler guarantee. The HTTP adapter must honor cancellation or timeout behavior, and the scheduler must know whether to retry later. Your README should distinguish the behavior you tested offline from what requires provider and network verification.
Project C — Make schema evolution a reviewed decision
The current page parser requires exactly three page properties and three item properties. Extend it to tolerate documented optional item fields while still rejecting missing required fields, wrong identity types and duplicate JSON keys. Define which unknown fields are ignored, which are preserved and which are rejected.
Test a harmless optional display name, an unknown field that violates your policy, a missing id, and an id with a wrong type. Keep the exported inventory schema stable unless you deliberately version it. Do not silently choose an arbitrary field as identity when the expected field is absent.
Project D — Write the real-provider adapter review
Before implementing a network adapter, prepare a review table covering endpoint, resource population, read permission, token audience, credential storage, redirects, response-size limits, error representation, pagination consistency, retry rules and cancellation. Link each provider-specific claim to its official documentation and record what needs a tenant test.
A passing offline client proves the fixture behavior. It does not prove that the actual endpoint supplies this schema, supports these cursors, uses stable totals, or permits the same retry policy. This review is how the course becomes useful beyond copied sample code: you can identify the differences that matter before connecting it to a live system.
Final acceptance and reasoning check
Deliver the program, tests, baseline response fixture, fault matrix and one completed extension. Your evidence must demonstrate two-page completion, a bounded retry, a non-retried forbidden request, an unrequested foreign link and a terminal count mismatch. State the accepted result grain and population scope.
Explain why status 200 is insufficient; why the final collected count needs reconciliation; why a permission failure is not repaired by an endless retry; why a missing second page cannot become an authoritative absence finding; and why a read retry helper cannot automatically provide exactly-once ticket creation.
The client is useful when its evidence boundary remains visible to the next system. Completing the website's learning check records study progress. It does not certify a provider integration or authorize changes to permissions, credentials or assets.
References: HTTP semantics in https://www.rfc-editor.org/rfc/rfc9110.html and Python's official json and urllib.parse documentation at https://docs.python.org/3/library/ . The fixture client is original course material and intentionally contains no real network adapter.
Transfer project — changed conditions
Build a mock client test for success, timeout-after-commit, 429 with bounded retry and a permanent authorization error. Add a paginated read with an empty final page and verify completion. Record request correlation and safe metadata without tokens or full personal data. Explain how changed payloads with a reused key should be handled according to the fictional contract rather than guessed by the client.
Practical assessment rubric
Score each dimension 0–2: 0 = absent or materially incorrect; 1 = partly correct with an unresolved gap; 2 = correct, explicit and supported by the supplied evidence or an actual labeled lab result.
- Evidence/model: identify the relevant entities, inputs, assumptions and boundaries without inventing facts.
- Main result: derive the case-specific expected result, calculation or decision and show the intermediate reasoning.
- Failure/boundary: test the changed condition and explain why the original conclusion does or does not transfer.
- Verification: supply reproducible steps and expected/observed results; label manual traces as manual, not executed.
- Communication/safety: explain limitations, owners and a proportionate next action without unsafe or unnecessary access.
Target: at least 8/10, with no zero in main result or communication/safety. This is a local learning rubric, not an accredited certification standard. A written/manual solution demonstrates reasoning only; operational competence additionally requires the relevant executable lab in an authorized environment. The native multiple-choice score is separate and does not automatically grade this rubric.
Submission template
- My input/evidence and assumptions:
- Expected result with calculations or trace:
- My implementation/decision and justification:
- Changed-condition result:
- Observed execution, or explicitly labeled manual trace:
- Failure and recovery evidence:
- Unverified limitation and next action:
- Self-score with evidence for each dimension:
Remediation
If the main result is wrong, reconstruct the supplied case from the raw inputs before changing code or controls. If the boundary case is wrong, identify the assumption that changed and rerun both the original and changed case. If verification is missing, do not convert a prediction into an observed result. Reattempt the transfer task without copying the worked solution, then explain it to another person.
Official reference for further study
Assessment: explain your decisions
Choose an answer and write your reason before opening each explanation. Then explain why the other choices do not fit the evidence. Use missed questions to revisit the lesson. This knowledge check is only one part of assessment: complete the practical transfer project as well. It does not predict certification-exam success.
1. How many rows are in the sample across both pages?
- Three
- Two
- One
Answer and explanation
Three — Two plus one equals three.
2. What should a throttled page become?
- An empty successful page
- A bounded retry or explicit incomplete result
- An infinite immediate retry
Answer and explanation
A bounded retry or explicit incomplete result — Completeness must not be silently lost.
3. Which data should be excluded from debug output?
- Status category
- Accepted count
- Authorization token
Answer and explanation
Authorization token — A token is a credential.
4. Page one returns HTTP 200, two items, next=page2 and total=3. Can a collector publish those two items as the completed inventory?
- No; follow approved pages and reconcile the terminal population.
- Yes, if the two item identities are unique.
- Yes, because HTTP 200 certifies complete collection.
Answer and explanation
No; follow approved pages and reconcile the terminal population. — HTTP success for a page is not terminal collection. The collector must follow the next-link contract and verify the final count; otherwise a later report can invent absence findings for omitted records.
5. A 429 response requests a 30-second delay, but the example client has a five-second delay budget. What should it do?
- Immediately retry three times to obtain a success response.
- Stop with a clear budget limitation so scheduling policy can decide what happens next.
- Wait five seconds and retry sooner than requested.
Answer and explanation
Stop with a clear budget limitation so scheduling policy can decide what happens next. — Capping a required supported delay downward would retry too soon. This small client refuses the long wait rather than pretending to support it. A scheduler or provider adapter can implement an approved deferral policy.
6. Page one points to a different origin for the next page. What should the narrow fixture collector do?
- Forward the same authentication automatically.
- Treat the first page as complete to avoid requesting the link.
- Reject the link before making a request to that origin.
Answer and explanation
Reject the link before making a request to that origin. — Pagination must stay within the adapter destination contract. Returning the first page as complete is also wrong. A real transport must validate redirects as well as explicit next links before forwarding credentials.
7. What does the timeout establish?
- The client lacks a response; the server may already have committed.
- No ticket was created.
- Exactly two tickets were created.
Answer and explanation
The client lacks a response; the server may already have committed. — Transport uncertainty does not determine server-side commit state. The fixture explicitly describes a committed ticket.
8. Which retry follows the supplied idempotency contract?
- Retry forever regardless of response.
- Same operation key and identical request within the supported window.
- A new random key on every attempt.
Answer and explanation
Same operation key and identical request within the supported window. — Stable operation identity is what allows the service to recognize the retry as the same intended action.
9. Should the client retry a persistent authorization error as if it were throttling?
- Yes; permissions always improve with repetition.
- Yes; increase the request rate.
- No; diagnose authorization rather than repeatedly sending the same invalid request.
Answer and explanation
No; diagnose authorization rather than repeatedly sending the same invalid request. — Authorization failure and transient throttling have different causes and recovery actions.
Open the scored course assessment to use the existing practice-test engine. Earlier attempts remain part of your history.
YOUR NEXT STEP
Keep building your skills
No directly related CogniSkill book is mapped to this course yet. Continue with the free learning, or compare the publishing catalogue by your next goal.
Explore books by topic and goal →Sign in to save lesson completion. Reading position is separate from completion.
Practice notes — your working space
Save predictions, outputs and explanations as you work. Notes stay on this browser, not your account; people sharing this browser can access them. Avoid passwords and sensitive data. Export to keep a portable copy, or clear your notes before leaving a shared device.
How was this lesson?
Help us improve this lesson.