Files
bongo/src/www/tests/test_mail_store.py
T
Mario Fetka ffac9dd290
Debian Trixie package bundle / packages (push) Successful in 21m32s
Add interactive web server administration
2026-07-22 07:56:02 +02:00

116 lines
4.6 KiB
Python

# /****************************************************************************
# * <Novell-copyright>
# * Copyright (c) 2001 Novell, Inc. All Rights Reserved.
# *
# * This program is free software; you can redistribute it and/or
# * modify it under the terms of version 2 of the GNU General Public License
# * as published by the Free Software Foundation.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, contact Novell, Inc.
# *
# * To contact Novell about this file by physical or electronic mail, you
# * may find current contact information at www.novell.com.
# * </Novell-copyright>
# ****************************************************************************/
import unittest
from types import SimpleNamespace
from bongo_web.mail_store import list_conversations, list_folders, read_conversation
class FakeStore:
def __init__(self):
self.closed = False
self.conversation_consumed = False
def Collections(self, path):
self.assert_path = path
return [SimpleNamespace(name="/mail/Archive"),
SimpleNamespace(name="/mail/INBOX")]
def Conversations(self, folder, props, start, end, showTotal):
item = SimpleNamespace(uid="abc", flags=2, props={
"bongo.from": "Example User <user@example.test>",
"nmap.conversation.subject": "Hello",
"nmap.conversation.date": "20260715T120000Z",
"nmap.conversation.unread": "1",
"nmap.conversation.count": "2",
})
result = iter([item])
# StoreClient's iterator supplies total; a simple iterator exercises fallback.
return result
def Conversation(self, uid, props=()):
item = SimpleNamespace(uid="b" * 32, flags=2, type=2)
def stream():
yield item
self.conversation_consumed = True
return stream()
def Read(self, uid):
if not self.conversation_consumed:
raise RuntimeError("nested Store command before iterator completion")
return (b"From: Example User <user@example.test>\r\n"
b"To: recipient@example.test\r\nSubject: Hello\r\n"
b"Content-Type: text/plain; charset=utf-8\r\n\r\nBody")
def Quit(self):
self.closed = True
class MailStoreTests(unittest.TestCase):
def test_inbox_is_first(self):
store = FakeStore()
folders = list_folders("u", "c", lambda _u, _c: store)
self.assertEqual(folders[0]["path"], "/mail/INBOX")
self.assertTrue(store.closed)
def test_conversation_values_are_structured(self):
stores = []
def factory(_user, _cookie):
store = FakeStore()
stores.append(store)
return store
result = list_conversations("u", "c", "/mail/INBOX", 0, 30, factory)
message = result["conversations"][0]
self.assertEqual(message["subject"], "Hello")
self.assertEqual(message["from"][0]["address"], "user@example.test")
def test_rejects_path_traversal_and_unbounded_page(self):
with self.assertRaises(ValueError):
list_conversations("u", "c", "/mail/../_system")
with self.assertRaises(ValueError):
list_conversations("u", "c", "/mail/INBOX", limit=101)
def test_reads_plain_text_conversation(self):
store = FakeStore()
result = read_conversation("u", "c", "a" * 32,
lambda _u, _c: store)
self.assertEqual(result["messages"][0]["text"], "Body")
self.assertEqual(result["messages"][0]["subject"], "Hello")
def test_extracts_canonical_mailing_list_id(self):
store = FakeStore()
store.Read = lambda _uid: (b"From: list@example.test\r\n"
b"List-ID: Example List <List.Example.Test>\r\n"
b"List-Post: <mailto:list@example.test>\r\n\r\nBody")
result = read_conversation("u", "c", "a" * 32,
lambda _u, _c: store)
self.assertEqual(result["messages"][0]["mailing_list"]["id"],
"list.example.test")
def test_rejects_store_command_in_conversation_id(self):
with self.assertRaises(ValueError):
read_conversation("u", "c", "abc READ /_system")
if __name__ == "__main__":
unittest.main()