fix: harden school imports and add optional feedback diagnostics

This commit is contained in:
Codex
2026-10-15 10:37:32 +08:00
parent 674df1ceb3
commit 7299f4d8b6
25 changed files with 722 additions and 42 deletions
+34
View File
@@ -62,6 +62,40 @@ def test_success_only_after_sender_accepted_and_retry_is_durable(service):
assert len(sender.messages) == 1
def test_diagnostic_log_is_extra_email_attachment_and_retry_stays_idempotent(service):
client, sender, _ = service
log = b'TPSchedule diagnostic log\n{"event":"login_opened"}\n'
files = [("submission_id", (None, ID)), ("type", (None, "problem")),
("message", (None, "Login stopped"))] + [
("attachments", (f"image-{i}.png", PNG, "image/png")) for i in range(3)] + [
("diagnostics", ("TPSchedule-diagnostics.txt", log, "text/plain; charset=utf-8"))]
assert client.post('/v1/feedback', files=files).status_code == 200
attachments = list(sender.messages[0].iter_attachments())
assert len(attachments) == 4
assert attachments[-1].get_filename() == 'TPSchedule-diagnostics.txt'
assert attachments[-1].get_payload(decode=True) == log
assert client.post('/v1/feedback', files=files).status_code == 200
assert len(sender.messages) == 1
@pytest.mark.parametrize('name,kind,data,mime,status', [
('diagnostics', 'problem', b'not a log', 'text/plain', 415),
('diagnostics', 'problem', b'TPSchedule diagnostic log\n\xff', 'text/plain', 415),
('diagnostics', 'problem', b'TPSchedule diagnostic log\n' + b'x' * (256 * 1024), 'text/plain', 413),
('diagnostics', 'development', b'TPSchedule diagnostic log\n', 'text/plain', 422),
], ids=['header', 'utf8', 'oversize', 'development'])
def test_invalid_diagnostics_never_send(service, name, kind, data, mime, status):
client, sender, _ = service
fields = [('submission_id', (None, ID)), ('type', (None, kind))]
if kind == 'problem':
fields += [('message', (None, 'Cannot import'))]
else:
fields += [('school', (None, 'University')), ('contact', (None, 'QQ123'))]
response = client.post('/v1/feedback', files=fields + [(name, ('log.txt', data, mime))])
assert response.status_code == status
assert not sender.messages
def test_reusing_id_with_other_content_rejected(service):
client, sender, _ = service
assert post(client).status_code == 200