tfc-mirror/tests/transmitter/test_packet.py

639 lines
27 KiB
Python

#!/usr/bin/env python3.7
# -*- coding: utf-8 -*-
"""
TFC - Onion-routed, endpoint secure messaging system
Copyright (C) 2013-2020 Markus Ottela
This file is part of TFC.
TFC is free software: you can redistribute it and/or modify it under the terms
of the GNU General Public License as published by the Free Software Foundation,
either version 3 of the License, or (at your option) any later version.
TFC 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 TFC. If not, see <https://www.gnu.org/licenses/>.
"""
import os
import struct
import time
import unittest
from multiprocessing import Queue
from unittest import mock
from typing import Any
from src.common.statics import (ASSEMBLY_PACKET_LENGTH, COMMAND, COMMAND_PACKET_QUEUE, C_A_HEADER, C_E_HEADER,
C_L_HEADER, C_S_HEADER, FILE, F_A_HEADER, F_E_HEADER, F_L_HEADER, F_S_HEADER,
GROUP_MSG_INVITE_HEADER, LOCAL_ID, MESSAGE, MESSAGE_PACKET_QUEUE, M_A_HEADER,
M_E_HEADER, M_L_HEADER, M_S_HEADER, RELAY_PACKET_QUEUE, SYMMETRIC_KEY_LENGTH,
TM_COMMAND_PACKET_QUEUE, TM_FILE_PACKET_QUEUE, TM_MESSAGE_PACKET_QUEUE,
WIN_TYPE_CONTACT, WIN_TYPE_GROUP)
from src.transmitter.packet import (cancel_packet, queue_command, queue_file, queue_message, queue_assembly_packets,
send_file, send_packet, split_to_assembly_packets)
from tests.mock_classes import (create_contact, create_group, create_keyset, Gateway, ContactList, KeyList,
nick_to_pub_key, OnionService, Settings, TxWindow, UserInput)
from tests.utils import cd_unit_test, cleanup, gen_queue_dict, tear_queue, tear_queues, TFCTestCase
class TestQueueMessage(unittest.TestCase):
def setUp(self) -> None:
"""Pre-test actions."""
self.queues = gen_queue_dict()
self.settings = Settings()
self.args = self.settings, self.queues
def tearDown(self) -> None:
"""Post-test actions."""
tear_queues(self.queues)
def test_private_message_header(self) -> None:
# Setup
user_input = UserInput(plaintext='Test message', type=MESSAGE)
window = TxWindow(log_messages=True)
window.window_contacts = [create_contact('Alice')]
# Test
self.assertIsNone(queue_message(user_input, window, *self.args))
self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 1)
def test_group_message_header(self) -> None:
# Setup
user_input = UserInput(plaintext='Test message', type=MESSAGE)
window = TxWindow(name='test_group',
type=WIN_TYPE_GROUP,
group=create_group('test_group'),
log_messages=True)
window.window_contacts = [create_contact('Alice')]
# Test
self.assertIsNone(queue_message(user_input, window, *self.args))
self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 1)
def test_group_management_message_header(self) -> None:
# Setup
user_input = UserInput(plaintext='Test message', type=MESSAGE)
window = TxWindow(log_messages=True)
window.window_contacts = [create_contact('Alice')]
# Test
self.assertIsNone(queue_message(user_input, window, *self.args, header=GROUP_MSG_INVITE_HEADER))
self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 1)
class TestSendFile(TFCTestCase):
def setUp(self) -> None:
"""Pre-test actions."""
self.unit_test_dir = cd_unit_test()
self.settings = Settings()
self.queues = gen_queue_dict()
self.window = TxWindow()
self.onion_service = OnionService()
self.contact_list = ContactList(nicks=['Alice', 'Bob', 'Charlie'])
self.args = self.settings, self.queues, self.window
def tearDown(self) -> None:
"""Post-test actions."""
cleanup(self.unit_test_dir)
tear_queues(self.queues)
def test_traffic_masking_raises_soft_error(self) -> None:
self.settings.traffic_masking = True
self.assert_se("Error: Command is disabled during traffic masking.", send_file, "testfile.txt", *self.args)
def test_missing_file_raises_soft_error(self) -> None:
self.assert_se("Error: File not found.", send_file, "testfile.txt", *self.args)
def test_empty_file_raises_soft_error(self) -> None:
# Setup
open('testfile.txt', 'wb+').close()
# Test
self.assert_se("Error: Target file is empty.", send_file, "testfile.txt", *self.args)
@mock.patch('time.sleep', return_value=None)
def test_file_transmission_to_contact(self, _: Any) -> None:
# Setup
self.window.window_contacts = [self.contact_list.get_contact_by_address_or_nick('Alice')]
self.window.type_print = 'contact'
input_data = os.urandom(5)
with open('testfile.txt', 'wb+') as f:
f.write(input_data)
# Test
self.assertIsNone(send_file("testfile.txt", *self.args))
self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 1)
self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(), 1)
@mock.patch('time.sleep', return_value=None)
def test_file_transmission_to_group(self, _: Any) -> None:
# Setup
self.window.window_contacts = [self.contact_list.get_contact_by_address_or_nick('Alice'),
self.contact_list.get_contact_by_address_or_nick('Bob')]
self.window.type_print = 'group'
input_data = os.urandom(5)
with open('testfile.txt', 'wb+') as f:
f.write(input_data)
self.assertIsNone(send_file("testfile.txt", *self.args))
self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 2)
self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(), 1)
class TestQueueFile(TFCTestCase):
file_list = ('tx_contacts', 'tx_groups', 'tx_keys', 'tx_login_data', 'tx_settings',
'rx_contacts', 'rx_groups', 'rx_keys', 'rx_login_data', 'rx_settings',
'tx_serial_settings.json', 'nc_serial_settings.json',
'rx_serial_settings.json', 'tx_onion_db')
def setUp(self) -> None:
"""Pre-test actions."""
self.unit_test_dir = cd_unit_test()
self.queues = gen_queue_dict()
def tearDown(self) -> None:
"""Post-test actions."""
cleanup(self.unit_test_dir)
tear_queues(self.queues)
@mock.patch('time.sleep', return_value=None)
@mock.patch('builtins.input', side_effect=file_list)
def test_tfc_database_raises_soft_error(self, *_: Any) -> None:
window = TxWindow(name='Alice',
type=WIN_TYPE_CONTACT,
type_print='contact',
uid=nick_to_pub_key("Alice"))
settings = Settings(traffic_masking=True,
disable_gui_dialog=True)
for file in self.file_list:
with open(file, 'wb+') as f:
f.write(b'a')
self.assert_se("Error: Can't send TFC database.", queue_file, window, settings, self.queues)
@mock.patch('shutil.get_terminal_size', return_value=[150, 150])
@mock.patch('builtins.input', side_effect=['./testfile.txt', 'No'])
def test_aborted_file(self, *_: Any) -> None:
# Setup
input_data = os.urandom(5)
with open('testfile.txt', 'wb+') as f:
f.write(input_data)
window = TxWindow(name='Alice',
type=WIN_TYPE_CONTACT,
type_print='contact',
uid=nick_to_pub_key("Alice"))
settings = Settings(traffic_masking=True,
disable_gui_dialog=True)
# Test
self.assert_se("File selection aborted.", queue_file, window, settings, self.queues)
@mock.patch('shutil.get_terminal_size', return_value=[150, 150])
@mock.patch('builtins.input', side_effect=['./testfile.txt', 'Yes'])
def test_file_queue_short_traffic_masking(self, *_: Any) -> None:
# Setup
input_data = os.urandom(5)
with open('testfile.txt', 'wb+') as f:
f.write(input_data)
window = TxWindow(name='Alice',
type=WIN_TYPE_CONTACT,
type_print='contact',
uid=nick_to_pub_key("Alice"),
log_messages=True)
settings = Settings(traffic_masking=True,
disable_gui_dialog=True)
# Test
self.assertIsNone(queue_file(window, settings, self.queues))
self.assertEqual(self.queues[TM_FILE_PACKET_QUEUE].qsize(), 1)
q_data, log_messages, log_as_ph = self.queues[TM_FILE_PACKET_QUEUE].get()
self.assertIsInstance(q_data, bytes)
self.assertTrue(log_messages)
self.assertTrue(log_as_ph)
@mock.patch('time.sleep', return_value=None)
@mock.patch('builtins.input', side_effect=['./testfile.txt', 'Yes'])
def test_file_queue_long_normal(self, *_: Any) -> None:
# Setup
input_data = os.urandom(2000)
with open('testfile.txt', 'wb+') as f:
f.write(input_data)
window = TxWindow(name='Alice',
type=WIN_TYPE_CONTACT,
type_print='contact',
uid=nick_to_pub_key("Alice"),
window_contacts=[create_contact('Alice')],
log_messages=True)
settings = Settings(traffic_masking=False,
disable_gui_dialog=True,
confirm_sent_files=True,
multi_packet_random_delay=True)
# Test
self.assertIsNone(queue_file(window, settings, self.queues))
self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(), 1)
@mock.patch('shutil.get_terminal_size', return_value=[150, 150])
@mock.patch('time.sleep', return_value=None)
@mock.patch('builtins.input', side_effect=['./testfile.txt', KeyboardInterrupt])
def test_keyboard_interrupt_raises_soft_error(self, *_: Any) -> None:
# Setup
input_data = os.urandom(2000)
with open('testfile.txt', 'wb+') as f:
f.write(input_data)
window = TxWindow(name='Alice',
type=WIN_TYPE_CONTACT,
type_print='contact',
uid=nick_to_pub_key("Alice"),
window_contacts=[create_contact('Alice')],
log_messages=True)
settings = Settings(traffic_masking=True,
disable_gui_dialog=True,
confirm_sent_files=True,
multi_packet_random_delay=True)
# Test
self.assert_se("File selection aborted.", queue_file, window, settings, self.queues)
self.assertEqual(self.queues[RELAY_PACKET_QUEUE].qsize(), 0)
class TestQueueCommand(unittest.TestCase):
def setUp(self) -> None:
"""Pre-test actions."""
self.settings = Settings()
self.queues = gen_queue_dict()
def tearDown(self) -> None:
"""Post-test actions."""
tear_queues(self.queues)
def test_queue_command(self) -> None:
self.assertIsNone(queue_command(os.urandom(200), self.settings, self.queues))
c_pt = self.queues[COMMAND_PACKET_QUEUE].get()
self.assertEqual(len(c_pt), ASSEMBLY_PACKET_LENGTH)
class TestSplitToAssemblyPackets(unittest.TestCase):
def test_short_message(self) -> None:
packet_list = split_to_assembly_packets(b'Short message', MESSAGE)
self.assertEqual(len(packet_list), 1)
self.assertTrue(packet_list[0].startswith(M_S_HEADER))
def test_long_message(self) -> None:
packet_list = split_to_assembly_packets(os.urandom(800), MESSAGE)
self.assertEqual(len(packet_list), 4)
self.assertTrue(packet_list[0].startswith(M_L_HEADER))
self.assertTrue(packet_list[1].startswith(M_A_HEADER))
self.assertTrue(packet_list[2].startswith(M_A_HEADER))
self.assertTrue(packet_list[3].startswith(M_E_HEADER))
def test_short_file(self) -> None:
packet_list = split_to_assembly_packets(os.urandom(50), FILE)
self.assertEqual(len(packet_list), 1)
self.assertTrue(packet_list[0].startswith(F_S_HEADER))
def test_long_file(self) -> None:
packet_list = split_to_assembly_packets(os.urandom(800), FILE)
self.assertEqual(len(packet_list), 4)
self.assertTrue(packet_list[0].startswith(F_L_HEADER + b'\x00\x00\x00\x00\x00\x00\x00\x04'))
self.assertTrue(packet_list[1].startswith(F_A_HEADER))
self.assertTrue(packet_list[2].startswith(F_A_HEADER))
self.assertTrue(packet_list[3].startswith(F_E_HEADER))
def test_short_command(self) -> None:
packet_list = split_to_assembly_packets(os.urandom(50), COMMAND)
self.assertEqual(len(packet_list), 1)
self.assertTrue(packet_list[0].startswith(C_S_HEADER))
def test_long_command(self) -> None:
packet_list = split_to_assembly_packets(os.urandom(800), COMMAND)
self.assertEqual(len(packet_list), 4)
self.assertTrue(packet_list[0].startswith(C_L_HEADER))
self.assertTrue(packet_list[1].startswith(C_A_HEADER))
self.assertTrue(packet_list[2].startswith(C_A_HEADER))
self.assertTrue(packet_list[3].startswith(C_E_HEADER))
class TestQueueAssemblyPackets(unittest.TestCase):
def setUp(self) -> None:
"""Pre-test actions."""
self.settings = Settings()
self.queues = gen_queue_dict()
self.window = TxWindow(uid=nick_to_pub_key("Alice"),
log_messages=True)
self.window.window_contacts = [create_contact('Alice')]
self.args = self.settings, self.queues, self.window
def tearDown(self) -> None:
"""Post-test actions."""
tear_queues(self.queues)
def test_queue_message_traffic_masking(self) -> None:
# Setup
packet_list = split_to_assembly_packets(os.urandom(200), MESSAGE)
self.settings.traffic_masking = True
# Test
self.assertIsNone(queue_assembly_packets(packet_list, MESSAGE, *self.args))
self.assertEqual(self.queues[TM_MESSAGE_PACKET_QUEUE].qsize(), 1)
packet, log_messages, log_as_ph = self.queues[TM_MESSAGE_PACKET_QUEUE].get()
self.assertIsInstance(packet, bytes)
self.assertTrue(log_messages)
self.assertFalse(log_as_ph)
def test_queue_message_normal(self) -> None:
# Setup
packet_list = split_to_assembly_packets(os.urandom(200), MESSAGE)
# Test
self.assertIsNone(queue_assembly_packets(packet_list, MESSAGE, *self.args))
self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 1)
packet, pub_key, log_setting, log_as_ph, win_uid = self.queues[MESSAGE_PACKET_QUEUE].get()
self.assertIsInstance(packet, bytes)
self.assertEqual(pub_key, nick_to_pub_key("Alice"))
self.assertEqual(win_uid, nick_to_pub_key("Alice"))
self.assertTrue(log_setting)
self.assertFalse(log_as_ph)
def test_queue_file_traffic_masking(self) -> None:
# Setup
packet_list = split_to_assembly_packets(os.urandom(200), FILE)
self.settings.traffic_masking = True
# Test
self.assertIsNone(queue_assembly_packets(packet_list, FILE, *self.args))
self.assertEqual(self.queues[TM_FILE_PACKET_QUEUE].qsize(), 1)
packet, log_messages, log_as_ph = self.queues[TM_FILE_PACKET_QUEUE].get()
self.assertIsInstance(packet, bytes)
self.assertTrue(log_messages)
self.assertFalse(log_as_ph)
def test_queue_command_traffic_masking(self) -> None:
# Setup
packet_list = split_to_assembly_packets(os.urandom(200), COMMAND)
self.settings.traffic_masking = True
# Test
self.assertIsNone(queue_assembly_packets(packet_list, COMMAND, *self.args))
self.assertEqual(self.queues[TM_COMMAND_PACKET_QUEUE].qsize(), 1)
data = self.queues[TM_COMMAND_PACKET_QUEUE].get()
self.assertIsInstance(data, bytes)
def test_queue_command_traffic_masking_no_window(self) -> None:
# Setup
self.window = None
packet_list = split_to_assembly_packets(os.urandom(200), COMMAND)
self.settings.traffic_masking = True
# Test
self.assertIsNone(queue_assembly_packets(packet_list, COMMAND, *self.args))
self.assertEqual(self.queues[TM_COMMAND_PACKET_QUEUE].qsize(), 1)
data = self.queues[TM_COMMAND_PACKET_QUEUE].get()
self.assertIsInstance(data, bytes)
def test_queue_command_normal(self) -> None:
# Setup
packet_list = split_to_assembly_packets(os.urandom(200), COMMAND)
# Test
self.assertIsNone(queue_assembly_packets(packet_list, COMMAND, *self.args))
self.assertEqual(self.queues[COMMAND_PACKET_QUEUE].qsize(), 1)
packet = self.queues[COMMAND_PACKET_QUEUE].get()
self.assertIsInstance(packet, bytes)
class TestSendPacket(unittest.TestCase):
"""\
This function is by far the most critical to security in Transmitter
Program, as it must detect the output of key material.
Plaintext length must always be evaluated to ensure constant
ciphertext length and hiding of output data type.
The most likely place for error is going to be the tx_harac
attribute of keyset, as it's the only data loaded from the sensitive
key database, and that is sent to the contact. An alternative place
could be a bug in the implementation where account strings would
incorrectly contain a byte string that contained key material, which
would cause Transmitter Program to leak keys to Networked Computer.
"""
def setUp(self) -> None:
"""Pre-test actions."""
self.l_queue = Queue()
self.key_list = KeyList(nicks=['Alice'])
self.settings = Settings()
self.gateway = Gateway()
self.onion_service = OnionService()
def tearDown(self) -> None:
"""Post-test actions."""
tear_queue(self.l_queue)
def test_message_length(self) -> None:
# Check that only 256-byte plaintext messages are ever allowed
pub_key = nick_to_pub_key("Alice")
for msg_len in range(1, 256):
with self.assertRaises(SystemExit):
send_packet(self.key_list, self.gateway, self.l_queue, bytes(msg_len), pub_key, True)
for msg_len in range(257, 300):
with self.assertRaises(SystemExit):
send_packet(self.key_list, self.gateway, self.l_queue, bytes(msg_len), pub_key, True)
def test_invalid_harac_raises_raises_struct_error(self) -> None:
# Check that in the case where an internal error caused bytestring (possible key material) to end up in hash
# ratchet value, the system raises some error that prevents the output of packet. In this case the, error comes
# from the unsuccessful encoding of hash ratchet counter.
for msg_len in range(1, 33):
key_list = KeyList()
key_list.keysets = [create_keyset('Alice',
tx_key=SYMMETRIC_KEY_LENGTH * b'\x02',
tx_harac=msg_len * b'k')] # <-- Intentional type error
with self.assertRaises(struct.error):
send_packet(key_list, self.gateway, self.l_queue,
bytes(ASSEMBLY_PACKET_LENGTH), nick_to_pub_key("Alice"), True)
def test_valid_message_packet(self) -> None:
# Setup
gateway = Gateway(serial_error_correction=5)
key_list = KeyList(master_key=bytes(SYMMETRIC_KEY_LENGTH))
key_list.keysets = [create_keyset('Alice',
tx_key=SYMMETRIC_KEY_LENGTH * b'\x02',
tx_harac=8)]
# Test
self.assertIsNone(send_packet(key_list, gateway, self.l_queue,
bytes(ASSEMBLY_PACKET_LENGTH), nick_to_pub_key("Alice"), True))
self.assertEqual(len(gateway.packets), 1)
time.sleep(0.01)
self.assertFalse(self.l_queue.empty())
def test_valid_command_packet(self) -> None:
"""Test that commands are output as they should.
Since command packets have no trailer, and since only user's
Receiver Program has local decryption key, encryption with any
key recipient is not already in possession of does not
compromise plaintext.
"""
# Setup
key_list = KeyList(master_key=bytes(SYMMETRIC_KEY_LENGTH))
key_list.keysets = [create_keyset(LOCAL_ID)]
# Test
self.assertIsNone(send_packet(key_list, self.gateway, self.l_queue,
bytes(ASSEMBLY_PACKET_LENGTH)))
self.assertEqual(len(self.gateway.packets), 1)
self.assertEqual(len(self.gateway.packets[0]), 345)
self.assertEqual(self.l_queue.qsize(), 1)
class TestCancelPacket(TFCTestCase):
def setUp(self) -> None:
"""Pre-test actions."""
self.queues = gen_queue_dict()
def tearDown(self) -> None:
"""Post-test actions."""
tear_queues(self.queues)
def test_cancel_message_during_normal(self) -> None:
# Setup
user_input = UserInput('cm')
settings = Settings()
window = TxWindow(name='Alice',
type=WIN_TYPE_CONTACT,
type_print='contact',
uid=nick_to_pub_key("Alice"))
window.window_contacts = [create_contact('Alice')]
self.queues[MESSAGE_PACKET_QUEUE].put(
('test_message1', nick_to_pub_key("Alice"), False, False, nick_to_pub_key("Alice")))
self.queues[MESSAGE_PACKET_QUEUE].put(
('test_message2', nick_to_pub_key("Charlie"), False, False, nick_to_pub_key("Charlie")))
self.queues[MESSAGE_PACKET_QUEUE].put(
('test_message3', nick_to_pub_key("Alice"), False, False, nick_to_pub_key("Alice")))
# Test
self.assert_se("Cancelled queued messages to contact Alice.",
cancel_packet, user_input, window, settings, self.queues)
self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 2)
def test_cancel_group_message_during_normal(self) -> None:
# Setup
user_input = UserInput('cm')
settings = Settings()
window = TxWindow(name='test_group',
type=WIN_TYPE_GROUP,
type_print='group',
uid='test_group')
window.window_contacts = [create_contact('Alice')]
self.queues[MESSAGE_PACKET_QUEUE].put(('test_message1', nick_to_pub_key("Alice"), False, False, 'test_group'))
self.queues[MESSAGE_PACKET_QUEUE].put(('test_message2', nick_to_pub_key("Alice"), False, False, 'test_group'))
# Test
self.assert_se("Cancelled queued messages to group test_group.",
cancel_packet, user_input, window, settings, self.queues)
self.assertEqual(self.queues[MESSAGE_PACKET_QUEUE].qsize(), 1) # Cancel packet
def test_cancel_message_during_traffic_masking(self) -> None:
# Setup
user_input = UserInput('cm')
settings = Settings(traffic_masking=True)
window = TxWindow()
window.window_contacts = [create_contact('Alice')]
self.queues[TM_MESSAGE_PACKET_QUEUE].put(('test_message1', {nick_to_pub_key("Alice"): False}))
self.queues[TM_MESSAGE_PACKET_QUEUE].put(('test_message2', {nick_to_pub_key("Alice"): False}))
# Test
self.assertIsNone(cancel_packet(user_input, window, settings, self.queues))
self.assertEqual(self.queues[TM_MESSAGE_PACKET_QUEUE].qsize(), 1) # Cancel packet in queue
def test_cancel_file_during_traffic_masking(self) -> None:
# Setup
user_input = UserInput('cf')
settings = Settings(traffic_masking=True)
window = TxWindow()
window.window_contacts = [create_contact('Alice')]
self.queues[TM_FILE_PACKET_QUEUE].put(('testfile1', {nick_to_pub_key("Alice"): False}))
self.queues[TM_FILE_PACKET_QUEUE].put(('testfile2', {nick_to_pub_key("Alice"): False}))
# Test
self.assertIsNone(cancel_packet(user_input, window, settings, self.queues))
self.assertEqual(self.queues[TM_FILE_PACKET_QUEUE].qsize(), 1)
def test_cancel_file_during_normal(self) -> None:
# Setup
user_input = UserInput('cf')
settings = Settings()
window = TxWindow(name='Alice',
type=WIN_TYPE_CONTACT,
type_print='contact',
uid=nick_to_pub_key("Alice"))
window.window_contacts = [create_contact('Alice')]
# Test
self.assert_se('Files are only queued during traffic masking.',
cancel_packet, user_input, window, settings, self.queues)
def test_cancel_file_when_nothing_to_cancel(self) -> None:
# Setup
user_input = UserInput('cf')
settings = Settings(traffic_masking=True)
window = TxWindow(name='Alice',
type=WIN_TYPE_CONTACT,
type_print='contact',
uid=nick_to_pub_key("Alice"))
window.window_contacts = [create_contact('Alice')]
# Test
self.assertIsNone(cancel_packet(user_input, window, settings, self.queues))
self.assertEqual(self.queues[TM_FILE_PACKET_QUEUE].qsize(), 0)
def test_cancel_message_when_nothing_to_cancel(self) -> None:
# Setup
user_input = UserInput('cm')
settings = Settings()
window = TxWindow(name='Alice',
type=WIN_TYPE_CONTACT,
type_print='contact',
uid=nick_to_pub_key("Alice"))
window.window_contacts = [create_contact('Alice')]
# Test
self.assert_se("No messages queued for contact Alice.",
cancel_packet, user_input, window, settings, self.queues)
self.assertEqual(self.queues[TM_FILE_PACKET_QUEUE].qsize(), 0)
if __name__ == '__main__':
unittest.main(exit=False)