|
9 | 9 | from labthings_fastapi.actions.invocation_model import LogRecordModel
|
10 | 10 |
|
11 | 11 |
|
12 |
| -class ThingOne(lt.Thing): |
| 12 | +class ThingThatLogsAndErrors(lt.Thing): |
13 | 13 | LOG_MESSAGES = [
|
14 | 14 | "message 1",
|
15 | 15 | "message 2",
|
16 | 16 | ]
|
17 | 17 |
|
18 | 18 | @lt.thing_action
|
19 |
| - def action_one(self, logger: lt.deps.InvocationLogger): |
| 19 | + def action_that_logs(self, logger: lt.deps.InvocationLogger): |
20 | 20 | for m in self.LOG_MESSAGES:
|
21 | 21 | logger.info(m)
|
22 | 22 |
|
| 23 | + @lt.thing_action |
| 24 | + def action_with_unhandled_error(self, logger: lt.deps.InvocationLogger): |
| 25 | + raise RuntimeError("I was asked to raise this error.") |
| 26 | + |
| 27 | + @lt.thing_action |
| 28 | + def action_with_invocation_error(self, logger: lt.deps.InvocationLogger): |
| 29 | + raise lt.exceptions.InvocationError("This is an error, but I handled it!") |
| 30 | + |
23 | 31 |
|
24 | 32 | def test_invocation_logging(caplog):
|
25 |
| - caplog.set_level(logging.INFO) |
26 |
| - server = lt.ThingServer() |
27 |
| - server.add_thing(ThingOne(), "/thing_one") |
28 |
| - with TestClient(server.app) as client: |
29 |
| - r = client.post("/thing_one/action_one") |
30 |
| - r.raise_for_status() |
31 |
| - invocation = poll_task(client, r.json()) |
32 |
| - assert invocation["status"] == "completed" |
33 |
| - assert len(invocation["log"]) == len(ThingOne.LOG_MESSAGES) |
34 |
| - for expected, entry in zip( |
35 |
| - ThingOne.LOG_MESSAGES, invocation["log"], strict=True |
36 |
| - ): |
37 |
| - assert entry["message"] == expected |
| 33 | + with caplog.at_level(logging.INFO, logger="labthings.action"): |
| 34 | + server = lt.ThingServer() |
| 35 | + server.add_thing(ThingThatLogsAndErrors(), "/log_and_error_thing") |
| 36 | + with TestClient(server.app) as client: |
| 37 | + r = client.post("/log_and_error_thing/action_that_logs") |
| 38 | + r.raise_for_status() |
| 39 | + invocation = poll_task(client, r.json()) |
| 40 | + assert invocation["status"] == "completed" |
| 41 | + assert len(invocation["log"]) == len(ThingThatLogsAndErrors.LOG_MESSAGES) |
| 42 | + assert len(invocation["log"]) == len(caplog.records) |
| 43 | + for expected, entry in zip( |
| 44 | + ThingThatLogsAndErrors.LOG_MESSAGES, invocation["log"], strict=True |
| 45 | + ): |
| 46 | + assert entry["message"] == expected |
| 47 | + |
| 48 | + |
| 49 | +def test_unhandled_error_logs(caplog): |
| 50 | + """Check that a log with a traceback is raised if there is an unhandled error.""" |
| 51 | + with caplog.at_level(logging.INFO, logger="labthings.action"): |
| 52 | + server = lt.ThingServer() |
| 53 | + server.add_thing(ThingThatLogsAndErrors(), "/log_and_error_thing") |
| 54 | + with TestClient(server.app) as client: |
| 55 | + r = client.post("/log_and_error_thing/action_with_unhandled_error") |
| 56 | + r.raise_for_status() |
| 57 | + invocation = poll_task(client, r.json()) |
| 58 | + assert invocation["status"] == "error" |
| 59 | + assert len(invocation["log"]) == len(caplog.records) == 1 |
| 60 | + assert caplog.records[0].levelname == "ERROR" |
| 61 | + # There is a traceback |
| 62 | + assert caplog.records[0].exc_info is not None |
| 63 | + |
| 64 | + |
| 65 | +def test_invocation_error_logs(caplog): |
| 66 | + """Check that a log with a traceback is raised if there is an unhandled error.""" |
| 67 | + with caplog.at_level(logging.INFO, logger="labthings.action"): |
| 68 | + server = lt.ThingServer() |
| 69 | + server.add_thing(ThingThatLogsAndErrors(), "/log_and_error_thing") |
| 70 | + with TestClient(server.app) as client: |
| 71 | + r = client.post("/log_and_error_thing/action_with_invocation_error") |
| 72 | + r.raise_for_status() |
| 73 | + invocation = poll_task(client, r.json()) |
| 74 | + assert invocation["status"] == "error" |
| 75 | + assert len(invocation["log"]) == len(caplog.records) == 1 |
| 76 | + assert caplog.records[0].levelname == "ERROR" |
| 77 | + # There is not a traceback |
| 78 | + assert caplog.records[0].exc_info is None |
38 | 79 |
|
39 | 80 |
|
40 | 81 | def test_logrecordmodel():
|
|
0 commit comments